/**
 * @function isNU0
 * @param { any } value
 * @description Will check if any is null/undefined/empty, accepts any type of data
 * @returns { Boolean }
 * @example
 * <pre>
 * [] = true
 * [[]] = true
 * {} = true
 * [{}] = true
 * [{}, [{}, [{}]]] = true
 * undefined = true
 * null = true
 * "" = true
 * 0 = false
 * false = false
 * </pre>
 */
function isNU0(value) {
    return isArray(value) ? !value.length || value.every(o => isNU0(o)) :
        isPlainObject(value) ? isObjectEmpty(value) :
            value === null ||
            value === undefined ||
            value === '';
}
function isArray(value) {
    return Array.isArray(value);
}
function isObjectEmpty(obj) {
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            return false;
        }
    }
    return true;
}
function isObject(value) {
    return value != null && typeof value === 'object' && Array.isArray(value) === false;
}
function isPlainObject(o) {
    function isObjectObject(v) {
        return isObject(v) === true && Object.prototype.toString.call(v) === '[object Object]';
    }
    var ctor, prot;
    if (isObjectObject(o) === false) return false;
    ctor = o.constructor;
    if (typeof ctor !== 'function') return false;
    prot = ctor.prototype;
    if (isObjectObject(o) === false) return false;
    if (prot.hasOwnProperty('isPrototypeOf') === false) return false;
    return true;
}
function removeFromArray(arr, key, value) {
    if (isNU0(arr)) return;
    let { length } = arr;
    while(length--){
        if (arr[length][key] === value) arr.splice(length, 1);
    }
}
function getSafe(obj, path) {
    if (isNU0(obj)) return;
    let pathArr = path.split('.'),
    { length } = pathArr,
    index = -1;
    while (++index < length) {
        obj = obj[pathArr[index]];
    }
    return obj;
}
function orderBy(arr, key) {
    if (isNU0(arr)) return;
	arr.sort((a, b) => {
		if (angular.isString(a[key])){
			return ''.concat(a[key]).localeCompare(b[key]);
		} else if (angular.isNumber(a[key])){
			return a[key] - b[key]
		}
    });
}
/**
 * @function fakePromise
 * @param { boolean } o
 * @returns A rejected or resolved promise base on the param "o", true for resolve, false for reject
 * @description Used to simulate a rest api return 
 */
function fakePromise(o) {
    return new Promise((resolve, reject) => {
        if (o) resolve({ data: [] });
        else reject();
    });
}
function injectNg(injectables, injectArr, scope){
    for (let i = 0, len = injectables.length; i < len; i++){
        scope[injectArr[i]] = injectables[i];
    }
}
function isScope(scope){
    return scope && scope.$evalAsync && scope.$watch;
}

angular.extend(global, {
    isNU0,
    isArray,
    isObjectEmpty,
    isObject,
    isPlainObject,
    removeFromArray,
    getSafe,
    orderBy,
    fakePromise,
    injectNg,
    isScope
});