import { combine_hash } from "../../../core/collection/array/combine_hash.js";
import { NumericInterval } from "../../../core/math/interval/NumericInterval.js";
import { computeHashFloat } from "../../../core/primitives/numbers/computeHashFloat.js";
import { computeStringHash } from "../../../core/primitives/strings/computeStringHash.js";

export class IKConstraint {

    /**
     * End bone that is going to be placed
     * @type {String}
     */
    effector = "";

    /**
     * How far should effector be from the contact, positive values result in effector not reaching the surface, and negative result in penetration
     * @example For a foot effector this would be distance above the ground
     * @type {number}
     */
    offset = 0;

    /**
     * Positive distance from the surface at which IK starts to take effect, low value represents full effect and high value represents where the influence begins
     * @type {NumericInterval}
     */
    distance = new NumericInterval(0, 0);

    /**
     *
     * @type {number}
     */
    strength = 1;

    /**
     *
     * @type {number}
     */
    limit = Math.PI;

    /**
     * Solver to be used for this constraint
     * @type {string}
     */
    solver = "2BIK";


    /**
     *
     * @param {IKConstraint} other
     */
    copy(other) {
        this.effector = other.effector;
        this.offset = other.offset;
        this.distance.copy(other.distance);
        this.strength = other.strength;
        this.limit = other.limit;
        this.solver = other.solver;
    }

    clone() {
        const r = new IKConstraint();

        r.copy(this);

        return r;
    }

    /**
     *
     * @param {IKConstraint} other
     * @returns {boolean}
     */
    equals(other) {
        return this.effector === other.effector
            && this.offset === other.offset
            && this.distance.equals(other.distance)
            && this.strength === other.strength
            && this.limit === other.limit
            && this.solver === other.solver;
    }

    /**
     *
     * @return {number}
     */
    hash() {
        return combine_hash(
            computeStringHash(this.effector),
            computeHashFloat(this.offset),
            this.distance.hash(),
            computeHashFloat(this.strength),
            computeHashFloat(this.limit),
            computeStringHash(this.solver)
        );
    }
}
