import {EventEmitter} from '../events/EventEmitter';

import { Equation } from "../equations/Equation";

export class Solver extends EventEmitter {

    /**
     * Gauss-Seidel solver.
     * @property GS
     * @type {Number}
     * @static
     */
    static GS: number = 1;

    type: any;
    /**
     * Current equations in the solver.
     *
     * @property equations
     * @type {Array}
     */
    equations: Equation[];
    /**
     * Function that is used to sort all equations before each solve.
     * @property equationSortFunction
     * @type {function|boolean}
     */
    equationSortFunction: any;

    /**
     * 解析器基类
     * Base class for constraint solvers.
     * @class Solver
     * @constructor
     * @extends EventEmitter
     */
    constructor(options?: any, type?: any) {
        options = options || {};

        super();

        this.type = type;


        this.equations = [];


        this.equationSortFunction = options.equationSortFunction || false;
    }


    /**
     * Method to be implemented in each subclass
     * @method solve
     * @param  {Number} dt
     * @param  {World} world
     */
    solve(dt,world) {
        throw new Error("Solver.solve should be implemented by subclasses!");
    };

    /**
     * Sort all equations using the .equationSortFunction. Should be called by subclasses before solving.
     * @method sortEquations
     */
    sortEquations() {
        if (this.equationSortFunction) {
            this.equations.sort(this.equationSortFunction);
        }
    };

    /**
     * Add an equation to be solved.
     *
     * @method addEquation
     * @param {Equation} eq
     */
    addEquation(eq) {
        if (eq.enabled) {
            this.equations.push(eq);
        }
    };

    /**
     * Add equations. Same as .addEquation, but this time the argument is an array of Equations
     *
     * @method addEquations
     * @param {Array} eqs
     */
    addEquations(eqs) {
        for (var i = 0, N = eqs.length; i !== N; i++) {
            var eq = eqs[i];
            if (eq.enabled) {
                this.equations.push(eq);
            }
        }
    };

    /**
     * Remove an equation.
     *
     * @method removeEquation
     * @param {Equation} eq
     */
    removeEquation(eq) {
        var i = this.equations.indexOf(eq);
        if (i !== -1) {
            this.equations.splice(i, 1);
        }
    };

    /**
     * Remove all currently added equations.
     *
     * @method removeAllEquations
     */
    removeAllEquations() {
        this.equations.length = 0;
    };


}