import { __values } from "tslib";
import * as Core from "@intelligentgraphics/ig.gfx.core";
import { LinearAlgebra, } from "@intelligentgraphics/ig.gfx.core";
/**
 * This abstract class combines all abstract information there is for a snap match.
 * The abstract isValid member (implemented in the child classes) should return true if the conditions for the snap match is set
 *
 * The first point passed to the constructor should always be the currently moving element!
 */
var SnapMatch = /** @class */ (function () {
    /**
     * The constructor of the SnapMode class. It calculates the common attributes of a snap match.
     * @param firstPoint the first point
     * @param secondPoint the second point
     * @param firstId the first id
     * @param secondId the second id
     */
    function SnapMatch(firstPoint, secondPoint, firstId, secondId) {
        var tDeltaX = secondPoint.transformedPoint.x - firstPoint.transformedPoint.x;
        var tDeltaY = secondPoint.transformedPoint.y - firstPoint.transformedPoint.y;
        var tDeltaZ = secondPoint.transformedPoint.z - firstPoint.transformedPoint.z;
        this.positionDifference = new Core.Float3(tDeltaX, tDeltaY, tDeltaZ);
        this.hasGhostModeRepresentation =
            secondPoint.representation === "Ghost" ||
                secondPoint.representation === "Ghost2";
        this.representation = secondPoint.representation;
        this.distance = Math.sqrt(tDeltaX * tDeltaX + tDeltaY * tDeltaY + tDeltaZ * tDeltaZ);
        this.xzDistance = Math.sqrt(tDeltaX * tDeltaX + tDeltaZ * tDeltaZ);
        // Normalize the rotation
        this.rotationDifference = Core.MathUtils.degToRad(secondPoint.rotation.y - firstPoint.rotation.y);
        if (this.rotationDifference < -1.5 * Math.PI) {
            this.rotationDifference += 2 * Math.PI;
        }
        else if (this.rotationDifference > 1.5 * Math.PI) {
            this.rotationDifference -= 2 * Math.PI;
        }
        this.centerOfRotation = secondPoint.transformedPoint;
        this.firstId = firstPoint.componentId || firstId;
        this.secondId = secondPoint.componentId || secondId;
        this.secondRootId = secondId;
        this.actionHolders = [
            firstPoint.componentId || firstId,
            secondPoint.componentId || secondId,
        ];
        this.canIntersectSnappedTo = false;
        this.firstType = firstPoint.type;
        this.secondType = secondPoint.type;
        this.firstKey = firstPoint.key;
        this.firstForeignKey = firstPoint.foreign;
        this.secondKey = secondPoint.key;
        this.secondForeignKey = secondPoint.foreign;
    }
    /**
     * @returns true if the distance of the match is small enough to count as a precise match
     */
    SnapMatch.prototype.isPrecise = function () {
        return this.distance < SnapMatch.preciseDistance;
    };
    /**
     * Adapts the previous transformation to execute the snap match taking care of rotation center and angle
     * @param previous
     * @returns the new transformation
     */
    SnapMatch.prototype.adaptTransformation = function (previous) {
        var notYetRotatedPosition = Core.Vector.Add3(previous.position, this.positionDifference);
        var adaptedPosition = LinearAlgebra.AdaptToRotation(this.rotationDifference, notYetRotatedPosition, this.centerOfRotation);
        var adaptedRotation = Core.Vector.Add3(previous.rotation, {
            x: 0,
            y: this.rotationDifference,
            z: 0,
        });
        return {
            position: adaptedPosition,
            rotation: adaptedRotation,
        };
    };
    SnapMatch.prototype.getActions = function () {
        var e_1, _a, e_2, _b;
        var actionsWithParentDependency = new Array();
        try {
            for (var _c = __values(this.actionHolders), _d = _c.next(); !_d.done; _d = _c.next()) {
                var actionHolder = _d.value;
                var actions = Core.State.API.GetActions(actionHolder);
                try {
                    for (var actions_1 = (e_2 = void 0, __values(actions)), actions_1_1 = actions_1.next(); !actions_1_1.done; actions_1_1 = actions_1.next()) {
                        var action = actions_1_1.value;
                        if (action.Mode === "ParentDependency") {
                            actionsWithParentDependency.push(action);
                        }
                    }
                }
                catch (e_2_1) { e_2 = { error: e_2_1 }; }
                finally {
                    try {
                        if (actions_1_1 && !actions_1_1.done && (_b = actions_1.return)) _b.call(actions_1);
                    }
                    finally { if (e_2) throw e_2.error; }
                }
            }
        }
        catch (e_1_1) { e_1 = { error: e_1_1 }; }
        finally {
            try {
                if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
            }
            finally { if (e_1) throw e_1.error; }
        }
        return actionsWithParentDependency;
    };
    /** The maximum distance between two points to allow for a snap match */
    SnapMatch.maxDistance = 0.2;
    /** The maximum rotation difference between two points to allow for a snap match. given in radians */
    SnapMatch.maxRotation = 55 * Core.Deg2Rad;
    /** Maximal distance for a precice snap match */
    SnapMatch.preciseDistance = 0.0025;
    return SnapMatch;
}());
export { SnapMatch };
