import { isNullOrUndefined } from "@intelligentgraphics/ig.utilities";
import { Float3 } from "./Types";
import { State } from "./State";
import Logger from "./Logger";
/** Representation of touches. A touch is either a mouse or a touch event. */
var Touch = /** @class */ (function () {
    function Touch(x, y) {
        this.x = x === undefined ? 0 : x;
        this.y = y === undefined ? 0 : y;
        this.button = 0;
        this.shiftKey = false;
        this.ctrlKey = false;
    }
    Touch.prototype.SetupFromEvent = function (event) {
        this.button = event.button;
        this.shiftKey = event.shiftKey;
        this.ctrlKey = event.ctrlKey;
    };
    return Touch;
}());
export { Touch };
/** Enumeration of main interaction modes. */
export var EInteractionMode;
(function (EInteractionMode) {
    /** Horizontal (x-z) interaction. */
    EInteractionMode[EInteractionMode["Horizontal"] = 1] = "Horizontal";
    /** Vertical (x-y) interaction. */
    EInteractionMode[EInteractionMode["Vertical"] = 2] = "Vertical";
})(EInteractionMode || (EInteractionMode = {}));
/** Tag for start position of Interactors. */
export var StartPosition = "Start";
/** Tag for end position of Interactors. */
export var EndPosition = "End";
/** This is a pre-defined interactor parameter.
 * If the value is false, "False", "false", the interactor is inactive
 * and should be ignored.
 */
export var Active = "Active";
/** This is a pre-defined interactor parameter.
 * If the value is true, "True", "true", the interactor is not available
 * for event-based interactions and should be ignored. Also, an up-traversal
 * should not stop on components with non-manual interactors.
 */
export var Manual = "Manual";
/** This is a pre-defined interactor parameter.
 * The value defines the stage an interactor belongs to. If undefined, the stage is 1.
 */
export var Stage = "Stage";
/** This is a pre-defined interactor parameter.
 * The value defines the time period in sec., an interactor wants to run in.
 * For a given stage, the maximum of all stage-related interactor periods will be the final period.
 * If undefined, the period is 1 sec.
 */
export var Period = "Period";
/** Abstract Interactor class as base class for all interactors. */
var Interactor = /** @class */ (function () {
    // FUNCTIONS
    /**
     * The Constructor, obviously.
     *
     * @param parameters The set of parameters, used to create the interactor.
     */
    function Interactor(parameters) {
        this.parameters = parameters;
        this.lastTouchPos = new Touch(undefined, undefined);
    }
    // UTILITIES:
    /**
     * Transform arc in Deg into range -180 - 180 Deg.
     *
     * @param degrees Arc in Deg.
     *
     * @returns Arc in Deg.
     */
    Interactor.NormalizeDegrees = function (degrees) {
        while (degrees < -180) {
            degrees += 360;
        }
        while (degrees > 180) {
            degrees -= 360;
        }
        return degrees;
    };
    /**
     * Transform arc in Rad into range -Pi/2 - Pi/2.
     *
     * @param radiant Arc in Rad.
     *
     * @returns Arc in Rad.
     */
    Interactor.NormalizeRadiant = function (radiant) {
        while (radiant < -Math.PI) {
            radiant += Math.PI + Math.PI;
        }
        while (radiant > Math.PI) {
            radiant -= Math.PI + Math.PI;
        }
        return radiant;
    };
    /**
     * Rotates a component around a fix point by specified y-axis arc.
     *
     * @param componentId The component to be rotated.
     * @param fixPoint The rotation center in MC coordinates.
     * @param arcRad The rotation angle in Rad.
     */
    Interactor.FixPointYRotation = function (componentId, fixPoint, arcRad) {
        var tRotation = State.API.GetYRotation(componentId);
        State.API.SetYRotation(componentId, tRotation + State.API.RAD2DEG * arcRad);
        var tPosition = State.API.GetPosition(componentId);
        State.API.SetPosition(componentId, new Float3((tPosition.x - fixPoint.x) * Math.cos(arcRad) +
            (tPosition.z - fixPoint.z) * Math.sin(arcRad) +
            fixPoint.x, tPosition.y, -(tPosition.x - fixPoint.x) * Math.sin(arcRad) +
            (tPosition.z - fixPoint.z) * Math.cos(arcRad) +
            fixPoint.z));
    };
    // STATIC FUNCTIONS
    Interactor.CreateFromConstructor = function (constructor, params) {
        return new constructor(params);
    };
    /**
     * Creates an interactor from a class name and parameters.
     *
     * @param className The fully qualified class name of an interactor class.
     * @param parameters A set of parameters specific to the interactor class.
     *
     * @returns The interactor instance or null.
     */
    Interactor.CreateFromClassName = function (className, parameters) {
        // Split the String on . to get the hierarchy
        var classHierarchy = className.split(".");
        var reference = window;
        for (var index = 0; index < classHierarchy.length; index++) {
            var prop = classHierarchy[index];
            reference = reference[prop];
            if (isNullOrUndefined(reference)) {
                break;
            }
        }
        if (!reference) {
            Logger.error("Could not find interactor constructor for: " + className);
            throw new Error("Could not find interactor constructor for: " + className);
        }
        return new reference(parameters || {});
    };
    /**
     * Set the associated component. To be used by drivers only!
     * @param id The component (id) the interactor is linked to.
     */
    Interactor.prototype.SetComponentId = function (id) {
        this.parameters.id = id;
    };
    /**
     * Access to the associated component.
     *
     * @retuns The id of the associated component, or null/undefined.
     */
    Interactor.prototype.GetComponentId = function () {
        return this.parameters.id;
    };
    /**
     * Access to the associated component. Deprecated function!
     *
     * @retuns The id of the associated component, or null/undefined.
     */
    Interactor.prototype.ComponentId = function () {
        console.log("Interactor.ComponentId() is deprecated! Use GetComponentId() instead");
        return this.parameters.id;
    };
    /**
     * Set to position "Start" or "End".
     *
     * @param position Must be "Start" or "End".
     */
    Interactor.prototype.SetPosition = function (position) {
        // console.log("Calling pure virtual Interactor.setPosition() for " + this.GetComponentId());
    };
    /**
     * Set the associated object(s) to a certain position. First the interactor must check
     * if the passed stage is the same as set for the interactor. Then it must apply the
     * position accordingly. Note. There is no implication about any sequence or direction,
     * the positions are set. Thus the interactor implementation must be functional without
     * any side effects.
     * @param stage The stage is either 1 or--in multi-staged animations--a number greater than 1.
     * @param position The position is a number from 0.0 to 1.0, relative to a stage.
     */
    Interactor.prototype.SetStagePosition = function (stage, position) {
        // console.log("Calling pure virtual Interactor.SetStagePosition() for " + this.GetComponentId());
    };
    /**
     * Initialization of position on interaction start.
     *
     * @param touch The touch event.
     */
    Interactor.prototype.SingleTouchStart = function (touch) {
        // console.log("Calling pure virtual Interactor.singleTouchStart() for " + this.GetComponentId());
    };
    /**
     * Handle single touch motion.
     *
     * @param touch The touch event.
     */
    Interactor.prototype.SingleTouchMotion = function (touch) {
        // console.log("Calling pure virtual Interactor.singleTouchMotion() for " + this.GetComponentId());
    };
    /**
     * Handle single touch end.
     *
     * @param touch The touch event.
     */
    Interactor.prototype.SingleTouchEnd = function (touch) {
        // console.warn('Interactor for ' + this.GetComponentId() + ' has no SingleTouchEnd(). Using SingleTouchMotion() as fallback.');
        this.SingleTouchMotion(touch);
    };
    /** Enables/disables logging. */
    Interactor.Log = false;
    // MATH AND BASIC CONSTANTS:
    /** Snap distance for positions. */
    Interactor.SNAP_POS_DISTANCE = 0.2;
    /** Snap distance for angles, in Deg. */
    Interactor.SNAP_ARC_DISTANCE_DEG = 55; // 45 + tolerance
    /** Snap distance for angles, in Rad. */
    Interactor.SNAP_ARC_DISTANCE_RAD = 0.9599; // 0.78534 + tolerance;
    // INTERACTION MODES:
    /** Interaction start mode. */
    Interactor.START = 1;
    /** Interaction motion mode */
    Interactor.MOTION = 2;
    /** Interaction end mode */
    Interactor.END = 3;
    // INTERACTOR OPERATION MODES:
    /** Interaction mode: Space planning in x-z plane. */
    Interactor.STANDARD_XZ = 1;
    /** Interaction mode: Space planning in x-z plane, y rotation. */
    Interactor.STANDARD_XZ__Y_ROT = 2;
    /** Interaction mode: Space planning in x-y plane. */
    Interactor.STANDARD_XY = 3;
    return Interactor;
}());
export { Interactor };
