"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
/**
 * Iterate over object properties
 *
 * @static
 * @template O
 * @template T
 * @param {O} obj
 * @param {<K extends keyof O>(key: K, value: O[K]) => T} callback
 * @returns {T[]}
 */
function iter(obj, callback) {
    if (!obj) {
        return [];
    }
    var result = [];
    for (var prop in obj) {
        result.push(callback(prop, obj[prop]));
    }
    return result;
}
exports.iter = iter;
/**
 * Generate new object from input
 *
 * @static
 * @template T
 * @param {T} source
 * @returns {T}
 */
function deepClone(source) {
    if (source === undefined || source === null || typeof source !== "object") {
        return source;
    }
    if (Array.isArray(source)) {
        return source.map(deepClone);
    }
    var result = {};
    for (var key in source) {
        var value = source[key];
        result[key] = deepClone(value);
    }
    return result;
}
exports.deepClone = deepClone;
/**
 * Deep merges source into target object
 *
 * @static
 * @template T
 * @template S
 * @param {T} target
 * @param {S} source
 * @returns
 */
function deepMerge(target, source) {
    if (!source && target) {
        return target;
    }
    if (!source && !target) {
        return {};
    }
    var result = target;
    for (var prop in source) {
        var value = source[prop];
        if (value === undefined) {
            continue;
        }
        if (typeof value !== "object") {
            result[prop] = value;
            continue;
        }
        result[prop] = deepMerge(result[prop] || {}, source[prop]);
    }
    return result;
}
exports.deepMerge = deepMerge;
/**
 *  Awaits all promise values of input object
 *
 * @static
 * @template R
 * @param {PromisifiedObject<R>} input
 * @param {LoadObjectDataOptions} [options]
 * @returns {Promise<R>}
 * @memberof Obj
 */
function loadObjectData(input, options) {
    return tslib_1.__awaiter(this, void 0, void 0, function () {
        var tOptions, tOutput_1, err_1;
        var _this = this;
        return tslib_1.__generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    tOptions = tslib_1.__assign({}, options);
                    _a.label = 1;
                case 1:
                    _a.trys.push([1, 3, , 4]);
                    tOutput_1 = {};
                    return [4 /*yield*/, Promise.all(Object.getOwnPropertyNames(input).map(function (prop) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
                            var rawValue, tValue, _a, _b, _c, err_2;
                            return tslib_1.__generator(this, function (_d) {
                                switch (_d.label) {
                                    case 0:
                                        _d.trys.push([0, 7, , 8]);
                                        rawValue = input[prop];
                                        if (!(typeof rawValue === "object" &&
                                            typeof rawValue["then"] === "function")) return [3 /*break*/, 2];
                                        return [4 /*yield*/, input[prop]];
                                    case 1:
                                        _a = _d.sent();
                                        return [3 /*break*/, 3];
                                    case 2:
                                        _a = input[prop];
                                        _d.label = 3;
                                    case 3:
                                        tValue = _a;
                                        if (!(tOptions.recursive &&
                                            typeof tValue === "object" &&
                                            !Array.isArray(tValue))) return [3 /*break*/, 5];
                                        _b = tOutput_1;
                                        _c = prop;
                                        return [4 /*yield*/, loadObjectData(tValue, tOptions)];
                                    case 4:
                                        _b[_c] = (_d.sent());
                                        return [3 /*break*/, 6];
                                    case 5:
                                        tOutput_1[prop] = tValue;
                                        _d.label = 6;
                                    case 6: return [3 /*break*/, 8];
                                    case 7:
                                        err_2 = _d.sent();
                                        if (tOptions.failOnValueReject) {
                                            throw err_2;
                                        }
                                        return [3 /*break*/, 8];
                                    case 8: return [2 /*return*/];
                                }
                            });
                        }); }))];
                case 2:
                    _a.sent();
                    return [2 /*return*/, tOutput_1];
                case 3:
                    err_1 = _a.sent();
                    throw err_1;
                case 4: return [2 /*return*/];
            }
        });
    });
}
exports.loadObjectData = loadObjectData;
/**
 * Transform values of object into something else
 *
 * @static
 * @template O
 * @template T Function return type
 * @param {O} input
 * @param {<K extends keyof O>(value: O[K], key: K) => T} callback
 * @returns transformed object
 * @memberof Obj
 */
function transform(input, callback) {
    var output = {};
    for (var prop in input) {
        output[prop] = callback(input[prop], prop);
    }
    return output;
}
exports.transform = transform;
exports.shallowEqual = function (a, b) {
    if (a === b) {
        return true;
    }
    var aKeys = Object.getOwnPropertyNames(a);
    var bKeys = Object.getOwnPropertyNames(b);
    if (aKeys.length !== bKeys.length) {
        return false;
    }
    for (var index = 0; index < aKeys.length; index++) {
        var aKey = aKeys[index];
        if (a[aKey] !== b[aKey]) {
            return false;
        }
        var bKey = bKeys[index];
        if (aKey !== bKey) {
            if (a[bKey] !== b[bKey]) {
                return false;
            }
        }
    }
    return true;
};
