import { __read, __spread, __values } from "tslib";
import * as Core from "@intelligentgraphics/ig.gfx.core";
import { NeighborType } from "../Types";
import * as Associates from "../Associates";
import { Category, MathUtils, State as CoreState, } from "@intelligentgraphics/ig.gfx.core";
/** This class is responsible for creating the world coordinate points of a component, given its state. */
var SnapPoints = /** @class */ (function () {
    /**
     * The constructor
     * @param state The state from which to calculate the world coordinates of the points
     * @param includeAllPoints whether to included the points of direct neighbors
     */
    function SnapPoints(state, includeAllPoints) {
        if (includeAllPoints === void 0) { includeAllPoints = true; }
        if (!state.transformation) {
            var position = CoreState.API.GetPosition(state.id);
            var degreesX = CoreState.API.GetXRotation(state.id);
            var degreesY = CoreState.API.GetYRotation(state.id);
            var degreesZ = CoreState.API.GetZRotation(state.id);
            state.transformation = {
                position: position,
                rotation: {
                    x: MathUtils.degToRad(degreesX),
                    y: MathUtils.degToRad(degreesY),
                    z: MathUtils.degToRad(degreesZ),
                },
            };
        }
        this.includeAllPoints = includeAllPoints;
        this.makeStrongNeighborPoints(state);
        this.makeStrongChildPoints(state);
        this.makeWeakPoints(state);
    }
    /**
     * Sets the weak snap points from the given state.
     * @param state The state of the component
     */
    SnapPoints.prototype.makeWeakPoints = function (state) {
        var tBounds = Core.State.API.GetBounds(state.id, "Local", true);
        if (!tBounds) {
            this.weakSnapPoints = [];
            return;
        }
        if (Category.hasCategory(state.id, Category.NicheContainer)) {
            this.weakSnapPoints = [];
            return;
        }
        this.weakSnapPoints = [
            { x: tBounds.min.x, z: tBounds.min.z },
            { x: tBounds.min.x, z: tBounds.max.z },
            { x: tBounds.max.x, z: tBounds.min.z },
            { x: tBounds.max.x, z: tBounds.max.z },
        ].map(function (pt) {
            var tPoint = new Core.Point(undefined, undefined, "Snap", new Core.Float3(pt.x, 0, pt.z), new Core.Float3(0, 0, 0));
            tPoint.ConvertForObject(state.transformation.position, state.transformation.rotation.y);
            return tPoint;
        });
    };
    /**
     * Sets the enabled strong snap points of the component, and adapts the to the given state
     * Note that if there is already a neighbor attached at a point, the point will be removed
     * @param state The state of the component
     */
    SnapPoints.prototype.makeStrongNeighborPoints = function (state) {
        var allValidNeighborTypes = NeighborType.allValidNeighborTypes().map(function (type) { return NeighborType.getAsString(type); });
        var rawPoints = Core.State.API.GetPoints(state.id);
        var filteredPoints = rawPoints.filter(function (pt) {
            return pt.enabled && allValidNeighborTypes.indexOf(pt.type) !== -1;
        });
        filteredPoints.forEach(function (point) {
            return point.ConvertForObject(state.transformation.position, state.transformation.rotation.y);
        });
        this.strongNeighborSnapPoints = filteredPoints;
        if (!this.includeAllPoints) {
            // filter out articles that have a neighbor snapped to it
            this.strongNeighborSnapPoints = this.strongNeighborSnapPoints.filter(function (point) {
                var pointType = NeighborType.getAsType(point.type);
                var neighbor = Associates.neighbor(state.id, pointType, point.key);
                return neighbor == undefined;
            });
        }
    };
    /**
     * Sets the strong child points.
     * @param state
     */
    SnapPoints.prototype.makeStrongChildPoints = function (state) {
        var e_1, _a;
        var unconvertedPoints = [];
        if (this.includeAllPoints || !Associates.parent(state.id)) {
            var originPoints = Core.State.API.GetPoints(state.id, null, null, "Origin");
            unconvertedPoints.push.apply(unconvertedPoints, __spread(originPoints));
        }
        var childPoints = Core.State.API.GetPoints(state.id, null, null, "Child");
        unconvertedPoints.push.apply(unconvertedPoints, __spread(childPoints));
        try {
            for (var unconvertedPoints_1 = __values(unconvertedPoints), unconvertedPoints_1_1 = unconvertedPoints_1.next(); !unconvertedPoints_1_1.done; unconvertedPoints_1_1 = unconvertedPoints_1.next()) {
                var point = unconvertedPoints_1_1.value;
                point.ConvertForObject(state.transformation.position, state.transformation.rotation.y);
            }
        }
        catch (e_1_1) { e_1 = { error: e_1_1 }; }
        finally {
            try {
                if (unconvertedPoints_1_1 && !unconvertedPoints_1_1.done && (_a = unconvertedPoints_1.return)) _a.call(unconvertedPoints_1);
            }
            finally { if (e_1) throw e_1.error; }
        }
        this.strongChildPoints = unconvertedPoints;
    };
    return SnapPoints;
}());
export default SnapPoints;
