var global = require('../internals/global');
var hide = require('../internals/hide');
var redefine = require('../internals/redefine');
var setGlobal = require('../internals/set-global');
var copyConstructorProperties = require('../internals/copy-constructor-properties');
var isForced = require('../internals/is-forced');

/*
  options.target     - name of the target object
  options.global     - target is the global object
  options.stat       - export as static methods of target
  options.proto      - export as prototype methods of target
  options.real       - real prototype method for the `pure` version
  options.forced     - export even if the native feature is available
  options.bind       - bind methods to the target, required for the `pure` version
  options.wrap       - wrap constructors to preventing global pollution, required for the `pure` version
  options.unsafe     - use the simple assignment of property instead of delete + defineProperty
  options.sham       - add a flag to not completely full polyfills
  options.enumerable - export as enumerable property
*/
module.exports = function (options, source) {
  var TARGET = options.target;
  var GLOBAL = options.global;
  var STATIC = options.stat;
  var FORCED, target, key, targetProperty, sourceProperty;
  if (GLOBAL) {
    target = global;
  } else if (STATIC) {
    target = global[TARGET] || setGlobal(TARGET, {});
  } else {
    target = (global[TARGET] || {}).prototype;
  }
  if (target) for (key in source) {
    targetProperty = target[key];
    sourceProperty = source[key];
    FORCED = isForced(GLOBAL ? key : TARGET + (STATIC ? '.' : '#') + key, options.forced);
    // contained in target
    if (!FORCED && targetProperty !== undefined) {
      if (typeof sourceProperty === typeof targetProperty) continue;
      copyConstructorProperties(sourceProperty, targetProperty);
    }
    // add a flag to not completely full polyfills
    if (options.sham || (targetProperty && targetProperty.sham)) {
      hide(sourceProperty, 'sham', true);
    }
    // extend global
    redefine(target, key, sourceProperty, options);
  }
};
