interface.js

const Helpers = require('./helpers');
const AssertionError = require('./errors');
let Interface = {};

/**
 * Check if is array
 * @param object {Object} object
 * @returns {boolean}
 */
Interface._isArray = (object) => {
    return Helpers.objectToString(object) === '[object Array]'
};

/**
 * Returns formatted arguments
 * @param args {Array}
 * @param pos {number}
 * @returns {string}
 */
Interface._printArgs = (args = [], pos = 0) => {
    let out = ``;
    for(let i=0; i<args.length; i++){
        if(Interface._isArray(args[i])){
            out += Interface._printArgs(args[i], i);
        } else {
            out += `args[${i + pos}]: ${args[i]}\n`;
        }
    }
    return out;
};

/**
 * Create interface all and any
 * @param obj {Object} object
 * @returns {Object}
 */
Interface.create = (obj) => {
    /**
     * @interface all
     * @description
     * All checks must be satisfied, can accept array or arguments
     * @example
     * be.all.true(true, true, false) // false;
     *
     */
    obj.all = {};

    /**
     * @interface any
     * @description
     * Also just one check can be satisfied, can accept array or arguments
     * @example
     * be.any.true(true, true, false) // true;
     *
     */
    obj.any = {};

    /**
     * @interface not
     * @description
     * return "logical not" of called method, accept one argument
     * @example
     * be.not.true(true) // false;
     *
     */
    obj.not = {};

    /**
     * @interface err
     * @description
     * Throw an Error if assertions are not satisfied
     * @param msg {string} optional error message
     * @param callback {function} optional function callback
     * @returns {error|void}
     * @since 1.8.0
     * @example
     * be.err.true(false) // Error;
     * be.err('an error message').true(false) // Error;
     * be.err().all.true(false, 1) // Error;
     * be.err(callback).all.true(false, 1) // Error;
     * be.err('your message', callback).all.boolean(false, true) // callback invoked;
     *
     */
    obj.err = (msg = '', callback = null) => {
        if (typeof msg === 'function') {
            obj.err.__last_error_message = '';
            obj.err.__last_error_callback = msg;
        } else {
            obj.err.__last_error_message = msg;
            obj.err.__last_error_callback = callback;
        }
        return obj.err;
    };

    /**
     * Last error message
     * @type {string}
     * @private
     */
    obj.err.__last_error_message = '';

    for (let i in obj) {
        if (obj.hasOwnProperty(i) && typeof obj[i] === 'function' && typeof obj[i]._ofBe === 'undefined') {
            obj.not[i] = (...params) => {
                return !obj[i].apply(this, params);
            };

            if (typeof obj[i].multiple === 'undefined') {
                obj.all[i] = (...params) => {
                    let args = params;

                    if (Interface._isArray(args[0]) && args.length === 1)
                        args = args[0];

                    if (!args.length) return false;

                    for (let a in args) {
                        if (args.hasOwnProperty(a) && !obj[i].call(this, args[a]))
                            return false;
                    }
                    return true;
                };

                obj.any[i] = (...params) => {
                    let args = params;
                    if (Interface._isArray(args[0]) && args.length === 1)
                        args = args[0];

                    for (let a in args) {
                        if (args.hasOwnProperty(a) && obj[i].call(this, args[a]))
                            return true;
                    }
                    return false;
                };
            }
        }

        // Build err
        if (typeof obj[i]._ofBe === 'undefined')
            if (typeof obj[i] === 'object') {
                for (let j in obj[i]) {
                    if (!obj.err[i])
                        obj.err[i] = {};
                    if (obj[i].hasOwnProperty(j)) {
                        obj.err[i][j] = (...params) => {
                            if (!obj[i][j].apply(this, params)) {
                                let errorMessage = obj.err.__last_error_message + '';
                                obj.err.__last_error_message = '';
                                //console.log(params.toString());
                                throw new AssertionError(
                                    errorMessage ? errorMessage : `${i}.${j} is not satisfied\n\n${Interface._printArgs(params)}\n`
                                );
                            } else if (typeof obj.err.__last_error_callback === 'function') {
                                obj.err.__last_error_callback();
                                obj.err.__last_error_callback = null;
                            }
                        }
                    }
                }
            } else {
                obj.err[i] = (...params) => {
                    if (!obj[i].apply(this, params)) {
                        let errorMessage = obj.err.__last_error_message + '';
                        obj.err.__last_error_message = '';
                        throw new AssertionError(
                            errorMessage ? errorMessage : `${i} is not satisfied\n\n${Interface._printArgs(params)}\n`
                        );
                    } else if (typeof obj.err.__last_error_callback === 'function') {
                        obj.err.__last_error_callback();
                        obj.err.__last_error_callback = null;
                    }
                }
            }
    }

    return obj;
};

module.exports = Interface;