/**
 * this module contains all the common functions used in the project
 * @author Aamir khan
 * @module utils/common
 */


import forEach from 'lodash/forEach';
import isObject from 'lodash/isObject';
import noop from 'lodash/noop';
import { makeLog } from './devOnly';
import curry from './functional/curry';


/**
 * @author Aamir khan
 * @desc player specific logger
 * @returns {void}
 */
export const log = makeLog("D-Player");


/**
 * just to log the warning that this functionis not implemented
 * @param {String} name - name of the function
 * @returns {Function}
*/
export const unImplemented = (name) => () => {
    log('%name function is not implemented'.replace('%name', name || 'this'));
}


/**
 * throw a global Error with the message
 * @throws a generic error with the given msg
 * @author Aamir khan
 * @returns {Function} a function that takes the msg as an argument
*/
export const panic = curry((emit, msg, err) => {
    emit('error', msg + (err ? '\n' + err.stack : ''));
    throw new Error(msg + (err ? '\n' + err.stack : ''));
});


export const yell = panic(noop);


// eslint-disable-next-line no-underscore-dangle
const _deepFreeze = (obj) => {
    forEach(Object.getOwnPropertyNames(obj), (key) => {
        const value = obj[key];
        if (isObject(value)) _deepFreeze(value);
    });
    return Object.freeze(obj);
};


/**
 * freeze the object deeply
 * @author Aamir khan
 * @param {Object} obj object to be freeze
 * @returns {Object} the same object that was passed in. 
 * @note the returned obj is the original one
 */
export const readOnlyObject = (obj) => {
    if (Object.freeze) {
        return _deepFreeze(obj);
    }
    return obj;
};


export const nop = noop;




/**
 * Determines whether an object has a property with the specified name.
 * @author Aamir khan
 * @returns {Boolean}
 */
export const has = Function.call.bind(Object.prototype.hasOwnProperty);