'use strict';

var keys = require('object-keys'); var hasSymbols = typeof Symbol === 'function' && typeof Symbol('foo') === 'symbol';

var toStr = Object.prototype.toString; var concat = Array.prototype.concat; var origDefineProperty = Object.defineProperty;

var isFunction = function (fn) {

return typeof fn === 'function' && toStr.call(fn) === '[object Function]';

};

var arePropertyDescriptorsSupported = function () {

var obj = {};
try {
        origDefineProperty(obj, 'x', { enumerable: false, value: obj });
        // eslint-disable-next-line no-unused-vars, no-restricted-syntax
        for (var _ in obj) { // jscs:ignore disallowUnusedVariables
                return false;
        }
        return obj.x === obj;
} catch (e) { /* this is IE 8. */
        return false;
}

}; var supportsDescriptors = origDefineProperty && arePropertyDescriptorsSupported();

var defineProperty = function (object, name, value, predicate) {

if (name in object && (!isFunction(predicate) || !predicate())) {
        return;
}
if (supportsDescriptors) {
        origDefineProperty(object, name, {
                configurable: true,
                enumerable: false,
                value: value,
                writable: true
        });
} else {
        object[name] = value;
}

};

var defineProperties = function (object, map) {

var predicates = arguments.length > 2 ? arguments[2] : {};
var props = keys(map);
if (hasSymbols) {
        props = concat.call(props, Object.getOwnPropertySymbols(map));
}
for (var i = 0; i < props.length; i += 1) {
        defineProperty(object, props[i], map[props[i]], predicates[props[i]]);
}

};

defineProperties.supportsDescriptors = !!supportsDescriptors;

module.exports = defineProperties;