import { assert } from "../../../assert.js";
import { orientation3_array } from "./orientation3_array.js";

/**
 * Ported from https://github.com/mikolalysenko/monotone-convex-hull-2d
 * @param {number[]|Float32Array|Float64Array} points
 * @param {number} [point_count]
 * @returns {number[]}
 */
export function convex_hull_monotone_2d(points, point_count = points.length * 0.5) {
    assert.isNumber(point_count, 'point_count');
    assert.isNonNegativeInteger(point_count, 'point_count');

    if (point_count < 3) {

        if (
            point_count === 2
            && points[0] === points[2]
            && points[1] === points[3]
        ) {

            return [0]

        }

        const result = new Array(point_count)

        for (let i = 0; i < point_count; ++i) {
            result[i] = i
        }

        return result
    }

    //Sort point indices along x-axis
    const sorted = new Array(point_count)

    for (let i = 0; i < point_count; ++i) {
        sorted[i] = i
    }

    sorted.sort(function (a, b) {
        const a2 = a * 2;
        const b2 = b * 2;

        var d = points[a2] - points[b2]

        if (d) {
            return d
        }

        return points[a2 + 1] - points[b2 + 1]
    })

    //Construct upper and lower hulls
    const lower = [sorted[0], sorted[1]]
    const upper = [sorted[0], sorted[1]]

    for (let i = 2; i < point_count; ++i) {
        const idx = sorted[i]

        //Insert into lower list
        let m = lower.length

        while (
            m > 1
            && orientation3_array(
                points,
                lower[m - 2],
                lower[m - 1],
                idx) <= 0
            ) {

            m -= 1
            lower.pop()

        }

        lower.push(idx)

        //Insert into upper list
        m = upper.length

        while (
            m > 1
            && orientation3_array(
                points,
                upper[m - 2],
                upper[m - 1],
                idx) >= 0
            ) {

            m -= 1
            upper.pop()

        }

        upper.push(idx)

    }

    //Merge lists together
    const result = new Array(upper.length + lower.length - 2)

    let ptr = 0

    for (var i = 0, nl = lower.length; i < nl; ++i) {
        result[ptr++] = lower[i]
    }

    for (var j = upper.length - 2; j > 0; --j) {
        result[ptr++] = upper[j]
    }


    //Return result
    return result
}
