/**
 * @license
 * Copyright Google LLC All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.io/license
 */

import {
  globalSources,
  patchEventPrototype,
  patchEventTarget,
  zoneSymbolEventNames,
} from '../common/events';
import {
  ADD_EVENT_LISTENER_STR,
  ArraySlice,
  attachOriginToPatched,
  bindArguments,
  FALSE_STR,
  isBrowser,
  isIEOrEdge,
  isMix,
  isNode,
  ObjectCreate,
  ObjectDefineProperty,
  ObjectGetOwnPropertyDescriptor,
  patchClass,
  patchMacroTask,
  patchMethod,
  patchOnProperties,
  REMOVE_EVENT_LISTENER_STR,
  TRUE_STR,
  wrapWithCurrentZone,
  ZONE_SYMBOL_PREFIX,
} from '../common/utils';
import {ZoneType} from '../zone-impl';

import {patchCallbacks} from './browser-util';
import {filterProperties, getOnEventNames} from './property-descriptor';

export function patchUtil(Zone: ZoneType): void {
  Zone.__load_patch('util', (global: any, Zone: ZoneType, api: _ZonePrivate) => {
    // Collect native event names by looking at properties
    // on the global namespace, e.g. 'onclick'.
    const eventNames: string[] = getOnEventNames(global);
    api.patchOnProperties = patchOnProperties;
    api.patchMethod = patchMethod;
    api.bindArguments = bindArguments;
    api.patchMacroTask = patchMacroTask;
    // In earlier version of zone.js (<0.9.0), we use env name `__zone_symbol__BLACK_LISTED_EVENTS`
    // to define which events will not be patched by `Zone.js`. In newer version (>=0.9.0), we
    // change the env name to `__zone_symbol__UNPATCHED_EVENTS` to keep the name consistent with
    // angular repo. The  `__zone_symbol__BLACK_LISTED_EVENTS` is deprecated, but it is still be
    // supported for backwards compatibility.
    const SYMBOL_BLACK_LISTED_EVENTS = Zone.__symbol__('BLACK_LISTED_EVENTS');
    const SYMBOL_UNPATCHED_EVENTS = Zone.__symbol__('UNPATCHED_EVENTS');
    if (global[SYMBOL_UNPATCHED_EVENTS]) {
      global[SYMBOL_BLACK_LISTED_EVENTS] = global[SYMBOL_UNPATCHED_EVENTS];
    }
    if (global[SYMBOL_BLACK_LISTED_EVENTS]) {
      (Zone as any)[SYMBOL_BLACK_LISTED_EVENTS] = (Zone as any)[SYMBOL_UNPATCHED_EVENTS] =
        global[SYMBOL_BLACK_LISTED_EVENTS];
    }
    api.patchEventPrototype = patchEventPrototype;
    api.patchEventTarget = patchEventTarget;
    api.isIEOrEdge = isIEOrEdge;
    api.ObjectDefineProperty = ObjectDefineProperty;
    api.ObjectGetOwnPropertyDescriptor = ObjectGetOwnPropertyDescriptor;
    api.ObjectCreate = ObjectCreate;
    api.ArraySlice = ArraySlice;
    api.patchClass = patchClass;
    api.wrapWithCurrentZone = wrapWithCurrentZone;
    api.filterProperties = filterProperties;
    api.attachOriginToPatched = attachOriginToPatched;
    api._redefineProperty = Object.defineProperty;
    api.patchCallbacks = patchCallbacks;
    api.getGlobalObjects = () => ({
      globalSources,
      zoneSymbolEventNames,
      eventNames,
      isBrowser,
      isMix,
      isNode,
      TRUE_STR,
      FALSE_STR,
      ZONE_SYMBOL_PREFIX,
      ADD_EVENT_LISTENER_STR,
      REMOVE_EVENT_LISTENER_STR,
    });
  });
}
