import { Vertex3 } from '../math';
import { TrackCoordinate3D } from './CoordinateTracker';

/**
 * Base class for tracked 3D points.
 * Point coordinates can be applied in both local and world space.
 */
export abstract class BimPointBase implements TrackCoordinate3D {
    protected _localX = 0;
    protected _localY = 0;
    protected _localZ = 0;

    protected _worldX: number;
    protected _worldY: number;
    protected _worldZ: number;

    protected _recalculateLocalCoords = false;
    protected _recalculateWorldCoords = false;

    /** X coordinate of point in world space. */
    public get x(): number {
        return this.recalculateOrGetWorldCoords().x;
    }

    /** Set the X coordinate of point in world space. */
    public set x(val: number) {
        this._worldX = val;
        this.recalculateOrGetLocalCoords(true);
    }

    /** Y coordinate of point in world space. */
    public get y(): number {
        return this.recalculateOrGetWorldCoords().y;
    }

    /** Set the Y coordinate of point in world space. */
    public set y(val: number) {
        this._worldY = val;
        this.recalculateOrGetLocalCoords(true);
    }

    /** Z coordinate of point in world space. */
    public get z(): number {
        return this.recalculateOrGetWorldCoords().z;
    }

    /** Set the Z coordinate of point in world space. */
    public set z(val: number) {
        this._worldZ = val;
        this.recalculateOrGetLocalCoords(true);
    }

    /** X coordinate of point in local space. */
    public get localX(): number {
        return this.recalculateOrGetLocalCoords().x;
    }

    /** Y coordinate of point in local space. */
    public get localY(): number {
        return this.recalculateOrGetLocalCoords().y;
    }

    /** Z coordinate of point in local space. */
    public get localZ(): number {
        return this.recalculateOrGetLocalCoords().z;
    }

    /**
     * Set coordinates in local space.
     * @param x X coordinate in local space.
     * @param y Y coordinate in local space.
     * @param z Z coordinate in local space.
     */
    public setLocals(x: number, y: number, z: number): void {
        this._localX = x;
        this._localY = y;
        this._localZ = z;
        this.recalculateOrGetWorldCoords(true);
    }

    /**
     * @hidden
     */
    public set recalculateWorldCoords(recalculate: boolean) {
        this._recalculateWorldCoords = recalculate;
    }

    protected abstract recalculateOrGetWorldCoords(force?: boolean): Vertex3;
    protected abstract recalculateOrGetLocalCoords(force?: boolean): Vertex3;
}
