import { Vector3, Camera, TransformNode } from '../loader/babylonjs-import';

import { Vertex3, copyVertex3ToRef, addVertexToRef } from './index';
import { PlaneUtil } from './plane';
import { Transforms } from './Transforms';

/** Contains utility functions for lines. */
export class LineUtil {
    /**
     * Creates a line from a center that is scaled with the camera distance to the plane
     * @param center Center point on the plane to create the line from
     * @param normal The normal of the plane
     * @param camera The camera used to scale the line size
     * @param scale The scale with which to scale the line with
     * @param parent The parent of which the parents world matrix is used to transform the points on the line with
     * @param dst An array of Vertex3 to put the result in
     * @returns The array dst, populated by the two new points making up a line on the plane
     */
    public static cameraScaledLineWithParentOnPlaneToRef<T extends Vertex3>(
        center: Vertex3,
        normal: Vertex3,
        camera: Camera,
        scale: number,
        parent: TransformNode,
        dst: [T, T]
    ): [T, T] {
        this.cameraScaledLineOnPlaneToRef(center, normal, camera, scale, dst);

        Transforms.TransformPointsWithParent<T>(parent, dst);

        return dst;
    }

    /**
     * @param center Center point on the plane to create the line from
     * @param normal The normal of the plane
     * @param camera The camera used to scale the line size
     * @param scale The scale with which to scale the line with
     * @param dst An array of Vertex3 to put the result in
     * @returns The array dst, populated by the two new points making up a line on the plane
     */
    public static cameraScaledLineOnPlaneToRef<T extends Vertex3>(
        center: Vertex3,
        normal: Vertex3,
        camera: Camera,
        scale: number,
        dst: [T, T]
    ): [T, T] {
        const { size } = PlaneUtil.createPlaneFromCamera(center, normal, camera, scale);

        return this.lineOnPlaneToRef(center, size, dst);
    }

    /**
     * Creates two points on a plane to form a line, from a point on that plane
     * @param centerOnPlane The center between the two points on the plane
     * @param size the size of the line, so the distance between the two points
     * @param dst An array of two vertex3 where the result is stored
     * @returns The same thing as the param dtys
     */
    public static lineOnPlaneToRef<T extends Vertex3>(centerOnPlane: Vertex3, size: number, dst: [T, T]): [T, T] {
        // TODO Ensure that center is actually on the plane!

        const vecInLine1 = new Vector3(1.0, 0.0, 0.0);
        const vecInLine2 = new Vector3(-1.0, 0.0, 0.0);

        for (let i = 0; i < dst.length; ++i) {
            copyVertex3ToRef(centerOnPlane, dst[i]);
        }

        addVertexToRef(vecInLine1.scaleInPlace(size), dst[0]);
        addVertexToRef(vecInLine2.scaleInPlace(size), dst[1]);
        return dst;
    }
}
