import { IKConstraint } from "./IKConstraint.js";


export class InverseKinematics {

    /**
     * @readonly
     * @type {IKConstraint[]}
     */
    constraints = [];

    /**
     *
     * @param {InverseKinematics} other
     */
    copy(other) {
        this.constraints.splice(0, this.constraints.length);

        const other_constraints = other.constraints;
        const n = other_constraints.length;

        for (let i = 0; i < n; i++) {
            const constraint = other_constraints[i];

            const constraintClone = constraint.clone();

            this.constraints.push(constraintClone);
        }
    }

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

        r.copy(this);

        return r;
    }

    /**
     *
     * @param {String} effector
     * @param {number} offset
     * @param {number} distanceMin
     * @param {number} distanceMax
     * @param {number} strength
     * @param {number} limit
     * @param {String} solver
     */
    add({
            effector,
            offset = 0,
            distanceMin = 0,
            distanceMax = 0.1,
            strength = 1,
            limit = Math.PI * 0.9,
            solver = "2BIK"
        }) {
        const c = new IKConstraint();

        c.effector = effector;
        c.offset = offset;
        c.strength = strength;
        c.distance.set(distanceMin, distanceMax);
        c.solver = solver;
        c.limit = limit;

        this.constraints.push(c);
    }

    /**
     *
     * @param {InverseKinematics} other
     * @returns {boolean}
     */
    equals(other) {
        const cs0 = this.constraints;
        const cs1 = other.constraints;

        const n0 = cs0.length;
        const n1 = cs1.length;

        if (n0 !== n1) {
            return false;
        }

        for (let i = 0; i < n0; i++) {
            const c0 = cs0[i];
            const c1 = cs1[i];
            if (!c0.equals(c1)) {
                return false;
            }
        }

        return true;
    }

    /**
     * @returns {number}
     */
    hash() {

        let hash = 0;
        const constraints = this.constraints;
        const length = constraints.length;

        for (let i = 0; i < length; i++) {
            const constraint = constraints[i];
            const singleValue = constraint.hash();
            hash = ((hash << 5) - hash) + singleValue;
            hash |= 0; // Convert to 32bit integer
        }

        return hash;
    }
}

InverseKinematics.typeName = "InverseKinematics";

