/** @internal NOTE: Internal APIs. Subject to change. Use of these APIs in production applications is not supported. */ /** */

import { Matrix } from './babylonjs-import';
import { Vertex3 } from '../math';

/**
 * Represents a coordinate system converter between the IFC and Babylon JS coordinate systems.
 */
class CoordinateSystems {
    /**
     * The transformation matrix used to convert coordinates from the IFC coordinate system to the Babylon JS coordinate system.
     */
    public readonly toBabylonTransform = Matrix.Identity();

    /**
     * The transformation matrix used to convert coordinates from Babylon.js to IFC coordinate system.
     */
    public readonly toIfcTransform: Matrix;

    /**
     * Constructs a new instance of the BabylonCoordinateSystem class.
     */
    public constructor() {
        this.toBabylonTransform.setRowFromFloats(1, 0, 0, 1, 0);
        this.toBabylonTransform.setRowFromFloats(2, 0, 1, 0, 0);
        this.toIfcTransform = this.toBabylonTransform.clone().invert();
    }

    /**
     * Converts an IFC coordinate to Babylon coordinate.
     * @param ifcVertex - The IFC vertex to be converted.
     * @returns The converted vertex.
     */
    public convertIfcCoordinateToBabylon<T extends Vertex3>(ifcVertex: T): T {
        this.convertCoordinateBetweenIfcAndBabylon(ifcVertex.x, ifcVertex.y, ifcVertex.z, ifcVertex);
        return ifcVertex;
    }

    /**
     * Converts the coordinates between the IFC (Industry Foundation Classes) and Babylon JS coordinate systems.
     *
     * @template T - The type of the destination vertex.
     * @param x - The x-coordinate in the source coordinate system.
     * @param y - The y-coordinate in the source coordinate system.
     * @param z - The z-coordinate in the source coordinate system.
     * @param dst - The destination vertex to store the converted coordinates.
     * @returns The destination vertex with the converted coordinates.
     */
    public convertCoordinateBetweenIfcAndBabylon<T extends Vertex3>(x: number, y: number, z: number, dst: T): T {
        dst.x = x;
        dst.y = z;
        dst.z = y;
        return dst;
    }

    /**
     * Converts an IFC transform matrix to a Babylon transform matrix in place.
     * The operations performed are equivalent to: bjsTransform = coordinateSystems.toBabylonTransform * m
     *
     * @param m The IFC transform matrix to be converted.
     * @returns The converted Babylon transform matrix.
     */
    public convertIfcTransformToBabylonTransformInPlace(m: Matrix): Matrix {
        // These operations should be the same as
        // bjsTransform = coordinateSystems.toBabylonTransform * m
        const a = m.m as number[];
        const _1 = a[1];
        a[1] = a[2];
        a[2] = _1;

        const _5 = a[5];
        a[5] = a[6];
        a[6] = _5;

        const _9 = a[9];
        a[9] = a[10];
        a[10] = _9;

        const _13 = a[13];
        a[13] = a[14];
        a[14] = _13;
        m.markAsUpdated();
        return m;
    }
}

/**
 * Helper to to transform between IFC and BabylonJS coordinate systems.
 */
export const coordinateSystems = new CoordinateSystems();
