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

/**
 * Simple algorithm for computing convex hull, not the fastest, but it does the job and has very small implementation
 * Please note that the result does not repeat the first vertex, meaning that the last point is not the same as the first point
 * NOTE: complexity is O(nh) where h is the number of point on the hull and n is number of input points
 * @see https://en.wikipedia.org/wiki/Gift_wrapping_algorithm
 * @param {number[]|Float32Array|Float64Array} input 2d point set, of form [x0,y0,x1,y1, ... xn,yn]
 * @param {number} point_count number of points in the input set
 * @returns {number[]} indices of vertices from input that make up the hull, this result is ordered to form a closed loop around the hull if followed
 */
export function convex_hull_jarvis_2d(input, point_count = input.length * 0.5) {
    assert.isNumber(point_count, 'point_count');
    assert.isNonNegativeInteger(point_count, 'point_count');

    const jarvis_vertices = [];

    if (point_count <= 2) {
        // special case, very small input
        for (let i = 0; i < point_count; i++) {
            jarvis_vertices.push(i);
        }

        return jarvis_vertices;
    }

    // find left-most point
    let l = 0;

    for (let i = 0; i < point_count; i++) {
        const i2 = i * 2;
        const l2 = l * 2;

        const x_i = input[i2];
        const x_l = input[l2];

        if (x_i < x_l) {
            l = i;
        }
    }

    let p = l, q;

    do {
        jarvis_vertices.push(p);

        q = (p + 1) % point_count;

        for (let i = 0; i < point_count; i++) {
            if (orientation3_array(input, p, q, i) > 0) {
                q = i;
            }
        }

        p = q;

    } while (
        input[p * 2] !== input[l * 2]
        || input[p * 2 + 1] !== input[l * 2 + 1]
        );

    return jarvis_vertices;
}
