Source: app/factory/Factory.js

'use strict';
/**
 * @module Factory
 */
const Map = require('../util/Map');

/**
 * 
 * @param {*} x 
 * @param {*} y 
 * @param {*} bounds
 * @return {boolean}
 * @function
 */
function withinBounds(x, y, bounds) {
    for (let i = 0; i < bounds.length; i ++) {
        if (x >= bounds[i][0].x && x <= bounds[i][1].x
            && y >= bounds[i][0].y && y <= bounds[i][1].y) {
            return true;
        }
    }
    return false;
}

/**
 * 
 * @param {*} bounds 
 * @return {Object}
 * @function
 */
function randInBounds(bounds) {
    let b = bounds[game.rnd.integerInRange(0, bounds.length -1 )];
    return {
        x: game.rnd.integerInRange(b[0].x, b[1].x),
        y: game.rnd.integerInRange(b[0].y, b[1].y),
    };
}

/**
 * 
 * 
 * @param {any} entity 
 * @param {any} group 
 * @param {Array} bounds
 * @param {number=} limit
 * @constructor Factory
 */
function Factory(entity, group, bounds, limit) {
    if (entity === undefined || bounds === undefined) {
        throw new TypeError('Undefined type?');
    }
    this.Entity = entity;
    this.group = group;
    this.bounds = bounds;
    this.limit = limit || Infinity;
    this.generated = 0;
}

/**
 * This will return a new `Entity` if the number of existing
 * `Entities` has not exceeded the `limit`.
 * 
 * @param {number} x
 * @param {number} y
 * @param {any} key
 * @return {Entity}
 */
Factory.prototype.next = function(x, y, key) {
    /**
     * Return nothing if limit has been reached
     */
    let living = this.group.countLiving();
    if ( living >= this.limit) return;
    if (x === null || y === null || !withinBounds(x, y, this.bounds)) {
        let o = randInBounds(this.bounds);
        x = o.x;
        y = o.y;
    }

    /**
     * Else, return a new entity and add it to the list.
     */
    let sprite = new this.Entity(x, y, key);
    this.group.add(sprite);
    sprite.setDirection(Math.floor(Math.random() * 4) + 1);
    sprite.idleHere();
    return sprite;
};

module.exports = Factory;