import { DynamicDrawUsage, LineBasicMaterial, LineSegments } from "three";
import { Float32BufferAttribute } from "three/src/core/BufferAttribute.js";
import { BufferGeometry } from "three/src/core/BufferGeometry.js";
import { assert } from "../../../core/assert.js";
import { array_copy } from "../../../core/collection/array/array_copy.js";

/**
 *
 * @param {number} capacity
 * @return {BufferGeometry}
 */
function buildGeometry(capacity) {
    assert.isNonNegativeInteger(capacity, 'capacity');

    const geometry = new BufferGeometry();

    geometry.dynamic = true;
    // no index

    const attribute_position = new Float32BufferAttribute(capacity * 3 * 2, 3, false);
    const attribute_color = new Float32BufferAttribute(capacity * 4 * 2, 4, false);

    attribute_position.setUsage(DynamicDrawUsage);
    attribute_color.setUsage(DynamicDrawUsage);

    geometry.setAttribute('position', attribute_position);
    geometry.setAttribute('color', attribute_color);

    return geometry;
}

export class Lines {

    constructor() {
        this.count = 0;
        this.capacity = 64;

        /**
         *
         * @type {BufferGeometry|null}
         */
        this.geometry = buildGeometry(this.capacity);

        this.mesh = new LineSegments(this.geometry, new LineBasicMaterial());

        // disable automatic culling/updates
        this.mesh.matrixAutoUpdate = false;
        this.mesh.frustumCulled = false;
        this.mesh.matrixWorldNeedsUpdate = false;

    }

    /**
     *
     * @param {number} x
     */
    setCount(x) {
        this.ensure_capacity(x);

        this.count = x;
        this.geometry.drawRange.count = x * 6;
    }

    /**
     *
     * @param {number} x
     */
    ensure_capacity(x) {
        if (this.capacity >= x) {
            // enough capacity
            return;
        }

        this.capacity = x;

        this.build();
    }

    /**
     *
     * @param {vec3} from
     * @param {vec3} to
     * @param {vec4} color
     */
    add_line(from, to, color) {
        const index = this.count;

        this.setCount(index + 1);


        const position_attribute = this.geometry.getAttribute('position');
        const color_attribute = this.geometry.getAttribute('color');

        const position_array = position_attribute.array;

        array_copy(from, 0, position_array, index * 6, 3);
        array_copy(to, 0, position_array, index * 6 + 3, 3);

        const color_array = color_attribute.array;

        array_copy(color, 0, color_array, index * 8, 4);
        array_copy(color, 0, color_array, index * 8 + 4, 4);


        this.geometry.drawRange.count = this.count;

        //
        position_attribute.needsUpdate = true;
        color_attribute.needsUpdate = true;

        console.warn('feature not fully implemented');
    }

    build() {

        const geometry = buildGeometry(this.capacity);

        // TODO copy existing attribute values

        this.geometry = geometry;

        this.mesh.geometry = geometry;

    }

    dispose() {
        this.geometry.dispose();

    }
}
