import { checkValueIsEmpty, isNil, isNotNil, isTrue, $any } from '@angular-ru/cdk/utils';

function replaceUndefinedOrNull(_, value) {
    return checkValueIsEmpty(value) ? undefined : value;
}

function clean(obj) {
    return JSON.parse(JSON.stringify(obj, replaceUndefinedOrNull));
}

function checkIsShallowEmpty(definition) {
    return Object.keys(clean(definition !== null && definition !== void 0 ? definition : {})).length === 0;
}

function deepClone(value) {
    return isNil(value) ? value : JSON.parse(JSON.stringify(value));
}

// eslint-disable-next-line max-lines-per-function
const deepFreeze = (value) => {
    const isObject = typeof value === 'object' && value !== null;
    const isDate = value instanceof Date;
    const skipFreeze = !isObject || isDate;
    if (skipFreeze) {
        return value;
    }
    Object.freeze(value);
    const oIsFunction = typeof value === 'function';
    const hasOwnProp = Object.prototype.hasOwnProperty;
    // eslint-disable-next-line complexity
    Object.getOwnPropertyNames(value).forEach((prop) => {
        if (hasOwnProp.call(value, prop) &&
            (oIsFunction ? prop !== 'caller' && prop !== 'callee' && prop !== 'arguments' : true) &&
            value[prop] !== null &&
            (typeof value[prop] === 'object' || typeof value[prop] === 'function') &&
            !Object.isFrozen(value[prop])) {
            deepFreeze(value[prop]);
        }
    });
    return value;
};

function firstKey(obj) {
    var _a;
    return (_a = Object.keys(obj !== null && obj !== void 0 ? obj : {})[0]) !== null && _a !== void 0 ? _a : null;
}

// eslint-disable-next-line complexity
function getValueByPath(obj, path, fallback = undefined) {
    var _a, _b, _c;
    if (((_a = path === null || path === void 0 ? void 0 : path.length) !== null && _a !== void 0 ? _a : 0) < 1) {
        return obj;
    }
    let result = obj;
    const parts = (_b = path === null || path === void 0 ? void 0 : path.split('.')) !== null && _b !== void 0 ? _b : [];
    let index = 0;
    for (; isNotNil(result) && index < parts.length; ++index) {
        const localIndex = parts === null || parts === void 0 ? void 0 : parts[index];
        result = (_c = result) === null || _c === void 0 ? void 0 : _c[localIndex];
    }
    return result !== null && result !== void 0 ? result : fallback;
}

function instanceOfPlainObject(plainObject) {
    return Object.prototype.toString.call(plainObject) === '[object Object]';
}

function isSimpleObject(value) {
    return isNotNil(value) && typeof value == 'object' && instanceOfPlainObject(value);
}

function isGetter(obj, prop) {
    var _a;
    let currentObj = obj;
    let result = false;
    if (isSimpleObject(currentObj)) {
        while (currentObj !== null) {
            if (isTrue(currentObj === null || currentObj === void 0 ? void 0 : currentObj.hasOwnProperty(prop))) {
                result = Boolean((_a = Object.getOwnPropertyDescriptor(currentObj, prop)) === null || _a === void 0 ? void 0 : _a.get);
                break;
            }
            else {
                currentObj = Object.getPrototypeOf(currentObj);
            }
        }
    }
    return result;
}

function isIterable(value) {
    return isNotNil(value) && typeof value[Symbol.iterator] === 'function';
}

function isObject(obj) {
    return obj === Object(obj);
}

function isPlainObject(plainObject) {
    let constructorRef;
    let prototypeRef;
    if (!instanceOfPlainObject(plainObject)) {
        return false;
    }
    // If has modified constructor
    // eslint-disable-next-line prefer-const
    constructorRef = plainObject.constructor;
    if (constructorRef === undefined) {
        return true;
    }
    // If has modified prototype
    // eslint-disable-next-line prefer-const
    prototypeRef = constructorRef.prototype;
    if (!instanceOfPlainObject(prototypeRef)) {
        return false;
    }
    // If constructor does not have an Object-specific method
    if (!prototypeRef.hasOwnProperty('isPrototypeOf')) {
        return false;
    }
    // Most likely a plain Object
    return true;
}

// eslint-disable-next-line complexity
function pathsOfObject(value, parentKey = null, keys = []) {
    for (const key in value) {
        if (!value.hasOwnProperty(key)) {
            continue;
        }
        const element = value[key];
        const isObjectValue = typeof element === 'object' && element !== null && !Array.isArray(element);
        // note: don't use isString for preserve circular dependencies
        const implicitKey = typeof parentKey === 'string' ? `${parentKey}.${key}` : key;
        if (isObjectValue) {
            pathsOfObject(value[key], implicitKey, keys);
        }
        else {
            keys.push(implicitKey);
        }
    }
    return keys;
}

function replaceWithNull(value) {
    return JSON.parse(JSON.stringify(value, (_, elem) => {
        if (typeof elem === 'object') {
            return elem;
        }
        return checkValueIsEmpty(elem) ? null : elem;
    }));
}

function shallowMapObject(object, mapper) {
    const result = {};
    for (const key in object) {
        if (object.hasOwnProperty(key)) {
            result[key] = mapper(object[key], key);
        }
    }
    return result;
}

function sortByAsc(key, a, b) {
    if ($any(a === null || a === void 0 ? void 0 : a[key]) > $any(b === null || b === void 0 ? void 0 : b[key])) {
        return 1;
    }
    else {
        return $any(a === null || a === void 0 ? void 0 : a[key]) < $any(b === null || b === void 0 ? void 0 : b[key]) ? -1 : 0;
    }
}

function sortByDesc(key, a, b) {
    if ($any(a === null || a === void 0 ? void 0 : a[key]) > $any(b === null || b === void 0 ? void 0 : b[key])) {
        return -1;
    }
    else {
        return $any(a === null || a === void 0 ? void 0 : a[key]) < $any(b === null || b === void 0 ? void 0 : b[key]) ? 1 : 0;
    }
}

function unwrap(target, options) {
    return Object.keys(target)
        .sort()
        .reduce((accumulator, key) => {
        var _a;
        return deepObjectReduce({
            key,
            accumulator,
            targetValue: (_a = target) === null || _a === void 0 ? void 0 : _a[key],
            options
        });
    }, {});
}
function flatten(object, excludeKeys = []) {
    const depthGraph = {};
    for (const key in object) {
        if (object.hasOwnProperty(key) && !excludeKeys.includes(key)) {
            mutate(object, depthGraph, key);
        }
    }
    return depthGraph;
}
function mutate(object, depthGraph, key) {
    const isObjectLike = typeof object[key] === 'object' && object[key] !== null;
    if (isObjectLike) {
        const flatObject = flatten(object[key]);
        for (const path in flatObject) {
            if (flatObject.hasOwnProperty(path)) {
                depthGraph[`${key}.${path}`] = flatObject[path];
            }
        }
    }
    else {
        depthGraph[key] = object[key];
    }
}
function deepObjectReduce({ accumulator, key, targetValue, options }) {
    let value = targetValue;
    if (isTrue(options.weekType)) {
        const isComplexType = typeof targetValue === 'object' && targetValue !== null;
        value = isComplexType ? targetValue : String(checkValueIsEmpty(targetValue) ? null : targetValue);
    }
    accumulator[key] = getComparableValue(options, value);
    return accumulator;
}
function comparable(target, options = {}) {
    let result = target;
    if (!isObject(result)) {
        return result;
    }
    if (Array.isArray(target)) {
        result = target.map((value) => getComparableValue(options, value));
    }
    else {
        result = unwrap(target, options);
    }
    return result;
}
function objectToString(obj, options = {}) {
    return JSON.stringify(comparable(obj, options));
}
function equals(a, b, options = {}) {
    return objectToString(a, options) === objectToString(b, options);
}
function shallowTrimProperties(obj) {
    return Object.entries(obj).reduce((result, [key, value]) => {
        // note: don't use isString for preserve circular dependencies
        result[key] = typeof value === 'string' ? value.trim() : value;
        return result;
    }, {});
}
function strictEquals(a, b) {
    const options = { weekType: true, deep: true };
    return objectToString(a, options) === objectToString(b, options);
}
function getComparableValue(options, value) {
    return isTrue(options.deep) ? comparable(value, options) : value;
}

/**
 * Generated bundle index. Do not edit.
 */

export { checkIsShallowEmpty, clean, comparable, deepClone, deepFreeze, deepObjectReduce, equals, firstKey, flatten, getComparableValue, getValueByPath, isGetter, isIterable, isObject, isPlainObject, isSimpleObject, mutate, objectToString, pathsOfObject, replaceWithNull, shallowMapObject, shallowTrimProperties, sortByAsc, sortByDesc, strictEquals, unwrap };
//# sourceMappingURL=angular-ru-cdk-object.js.map
