/*!
 * Microsoft Dynamic Proto Utility, 2.0.3
 * Copyright (c) Microsoft and contributors. All rights reserved.
 */
System.register('Microsoft.DynamicProto-JS', [], (function (exports) {
    'use strict';
    return {
        execute: (function () {

            exports('default', dynamicProto);

            var UNDEF_VALUE = undefined;
            var NULL_VALUE = null;
            var EMPTY = "";
            var FUNCTION = "function";
            var NUMBER = "number";
            var OBJECT = "object";
            var PROTOTYPE = "prototype";
            var UNDEFINED = "undefined";
            var CALL = "call";
            var ObjClass = Object;
            var ObjProto = ObjClass[PROTOTYPE];

            function safeGet(cb, defValue) {
                var result = defValue;
                try {
                    result = cb();
                }
                catch (e) {
                }
                return result;
            }

            function _createIs(theType) {
                return function (value) {
                    return typeof value === theType;
                };
            }
            function _createObjIs(theName) {
                var theType = "[object " + theName + "]";
                return function (value) {
                    return !!(value && objToString(value) === theType);
                };
            }
            function objToString(value) {
                return ObjProto.toString[CALL](value);
            }
            var isNumber = ( _createIs(NUMBER));
            var isError = ( _createObjIs("Error"));

            function objHasOwnProperty(obj, prop) {
                return obj && ObjProto.hasOwnProperty[CALL](obj, prop);
            }

            function throwTypeError(message) {
                throw new TypeError(message);
            }

            var GLOBAL_CONFIG_KEY = "__tsUtils$gblCfg";
            var _globalCfg;
            function _getGlobalValue() {
                var result;
                if (typeof globalThis !== UNDEFINED) {
                    result = globalThis;
                }
                if (!result && typeof self !== UNDEFINED) {
                    result = self;
                }
                if (!result && typeof window !== UNDEFINED) {
                    result = window;
                }
                if (!result && typeof global !== UNDEFINED) {
                    result = global;
                }
                return result;
            }
            function _getGlobalConfig() {
                if (!_globalCfg) {
                    var gbl = _getGlobalValue() || {};
                    _globalCfg = gbl[GLOBAL_CONFIG_KEY] = gbl[GLOBAL_CONFIG_KEY] || {};
                }
                return _globalCfg;
            }

            function dumpObj(object, format) {
                var propertyValueDump = EMPTY;
                if (isError(object)) {
                    propertyValueDump = "{ stack: '" + object.stack + "', message: '" + object.message + "', name: '" + object.name + "'";
                }
                else {
                    try {
                        propertyValueDump = JSON.stringify(object, NULL_VALUE, format ? (isNumber(format) ? format : 4) : UNDEF_VALUE);
                    }
                    catch (e) {
                        propertyValueDump = " - " + dumpObj(e, format);
                    }
                }
                return objToString(object) + ": " + propertyValueDump;
            }

            var objDefineProp = ObjClass["defineProperty"];

            var _globalLazyTestHooks;
            var _fetchLazyTestHooks = function () {
                _globalLazyTestHooks = _getGlobalConfig();
                _fetchLazyTestHooks = NULL_VALUE;
            };
            function getLazy(cb) {
                var lazyValue = {};
                _fetchLazyTestHooks && _fetchLazyTestHooks();
                lazyValue.b = _globalLazyTestHooks.lzy;
                objDefineProp(lazyValue, "v", {
                    configurable: true,
                    get: function () {
                        var result = cb();
                        if (!_globalLazyTestHooks.lzy) {
                            objDefineProp(lazyValue, "v", {
                                value: result
                            });
                            if (lazyValue.b) {
                                delete lazyValue.b;
                            }
                        }
                        if (_globalLazyTestHooks.lzy && lazyValue.b !== _globalLazyTestHooks.lzy) {
                            lazyValue.b = _globalLazyTestHooks.lzy;
                        }
                        return result;
                    }
                });
                return lazyValue;
            }

            function safeGetLazy(cb, defValue) {
                return getLazy(function () { return safeGet(cb, defValue); });
            }

            var _cachedGlobal;
            function getGlobal(useCached) {
                (!_cachedGlobal || useCached === false || (_globalLazyTestHooks && _globalLazyTestHooks.lzy && !_cachedGlobal.b)) && (_cachedGlobal = safeGetLazy(_getGlobalValue, NULL_VALUE));
                return _cachedGlobal.v;
            }

            var objCreate = ObjClass["create"] || polyObjCreate;
            function polyObjCreate(obj) {
                if (!obj) {
                    return {};
                }
                var type = typeof obj;
                if (type !== OBJECT && type !== FUNCTION) {
                    throw new TypeError("Prototype must be an Object or function: " + dumpObj(obj));
                }
                function tempFunc() { }
                tempFunc[PROTOTYPE] = obj;
                return new tempFunc();
            }

            var _a;
            var Constructor = 'constructor';
            var Prototype = 'prototype';
            var strFunction = 'function';
            var DynInstFuncTable = '_dynInstFuncs';
            var DynProxyTag = '_isDynProxy';
            var DynClassName = '_dynClass';
            var DynClassNamePrefix = '_dynCls$';
            var DynInstChkTag = '_dynInstChk';
            var DynAllowInstChkTag = DynInstChkTag;
            var DynProtoDefaultOptions = '_dfOpts';
            var UnknownValue = '_unknown_';
            var str__Proto = "__proto__";
            var DynProtoBaseProto = "_dyn" + str__Proto;
            var DynProtoGlobalSettings = "__dynProto$Gbl";
            var DynProtoCurrent = "_dynInstProto";
            var strUseBaseInst = 'useBaseInst';
            var strSetInstFuncs = 'setInstFuncs';
            var Obj = Object;
            var _objGetPrototypeOf = Obj["getPrototypeOf"];
            var _objGetOwnProps = Obj["getOwnPropertyNames"];
            var _gbl = getGlobal();
            var _gblInst = _gbl[DynProtoGlobalSettings] || (_gbl[DynProtoGlobalSettings] = {
                o: (_a = {},
                    _a[strSetInstFuncs] = true,
                    _a[strUseBaseInst] = true,
                    _a),
                n: 1000
            });
            function _isObjectOrArrayPrototype(target) {
                return target && (target === Obj[Prototype] || target === Array[Prototype]);
            }
            function _isObjectArrayOrFunctionPrototype(target) {
                return _isObjectOrArrayPrototype(target) || target === Function[Prototype];
            }
            function _getObjProto(target) {
                var newProto;
                if (target) {
                    if (_objGetPrototypeOf) {
                        return _objGetPrototypeOf(target);
                    }
                    var curProto = target[str__Proto] || target[Prototype] || (target[Constructor] ? target[Constructor][Prototype] : null);
                    newProto = target[DynProtoBaseProto] || curProto;
                    if (!objHasOwnProperty(target, DynProtoBaseProto)) {
                        delete target[DynProtoCurrent];
                        newProto = target[DynProtoBaseProto] = target[DynProtoCurrent] || target[DynProtoBaseProto];
                        target[DynProtoCurrent] = curProto;
                    }
                }
                return newProto;
            }
            function _forEachProp(target, func) {
                var props = [];
                if (_objGetOwnProps) {
                    props = _objGetOwnProps(target);
                }
                else {
                    for (var name_1 in target) {
                        if (typeof name_1 === "string" && objHasOwnProperty(target, name_1)) {
                            props.push(name_1);
                        }
                    }
                }
                if (props && props.length > 0) {
                    for (var lp = 0; lp < props.length; lp++) {
                        func(props[lp]);
                    }
                }
            }
            function _isDynamicCandidate(target, funcName, skipOwn) {
                return (funcName !== Constructor && typeof target[funcName] === strFunction && (skipOwn || objHasOwnProperty(target, funcName)) && funcName !== str__Proto && funcName !== Prototype);
            }
            function _throwTypeError(message) {
                throwTypeError("DynamicProto: " + message);
            }
            function _getInstanceFuncs(thisTarget) {
                var instFuncs = objCreate(null);
                _forEachProp(thisTarget, function (name) {
                    if (!instFuncs[name] && _isDynamicCandidate(thisTarget, name, false)) {
                        instFuncs[name] = thisTarget[name];
                    }
                });
                return instFuncs;
            }
            function _hasVisited(values, value) {
                for (var lp = values.length - 1; lp >= 0; lp--) {
                    if (values[lp] === value) {
                        return true;
                    }
                }
                return false;
            }
            function _getBaseFuncs(classProto, thisTarget, instFuncs, useBaseInst) {
                function _instFuncProxy(target, funcHost, funcName) {
                    var theFunc = funcHost[funcName];
                    if (theFunc[DynProxyTag] && useBaseInst) {
                        var instFuncTable = target[DynInstFuncTable] || {};
                        if (instFuncTable[DynAllowInstChkTag] !== false) {
                            theFunc = (instFuncTable[funcHost[DynClassName]] || {})[funcName] || theFunc;
                        }
                    }
                    return function () {
                        return theFunc.apply(target, arguments);
                    };
                }
                var baseFuncs = objCreate(null);
                _forEachProp(instFuncs, function (name) {
                    baseFuncs[name] = _instFuncProxy(thisTarget, instFuncs, name);
                });
                var baseProto = _getObjProto(classProto);
                var visited = [];
                while (baseProto && !_isObjectArrayOrFunctionPrototype(baseProto) && !_hasVisited(visited, baseProto)) {
                    _forEachProp(baseProto, function (name) {
                        if (!baseFuncs[name] && _isDynamicCandidate(baseProto, name, !_objGetPrototypeOf)) {
                            baseFuncs[name] = _instFuncProxy(thisTarget, baseProto, name);
                        }
                    });
                    visited.push(baseProto);
                    baseProto = _getObjProto(baseProto);
                }
                return baseFuncs;
            }
            function _getInstFunc(target, funcName, proto, currentDynProtoProxy) {
                var instFunc = null;
                if (target && objHasOwnProperty(proto, DynClassName)) {
                    var instFuncTable = target[DynInstFuncTable] || objCreate(null);
                    instFunc = (instFuncTable[proto[DynClassName]] || objCreate(null))[funcName];
                    if (!instFunc) {
                        _throwTypeError("Missing [" + funcName + "] " + strFunction);
                    }
                    if (!instFunc[DynInstChkTag] && instFuncTable[DynAllowInstChkTag] !== false) {
                        var canAddInst = !objHasOwnProperty(target, funcName);
                        var objProto = _getObjProto(target);
                        var visited = [];
                        while (canAddInst && objProto && !_isObjectArrayOrFunctionPrototype(objProto) && !_hasVisited(visited, objProto)) {
                            var protoFunc = objProto[funcName];
                            if (protoFunc) {
                                canAddInst = (protoFunc === currentDynProtoProxy);
                                break;
                            }
                            visited.push(objProto);
                            objProto = _getObjProto(objProto);
                        }
                        try {
                            if (canAddInst) {
                                target[funcName] = instFunc;
                            }
                            instFunc[DynInstChkTag] = 1;
                        }
                        catch (e) {
                            instFuncTable[DynAllowInstChkTag] = false;
                        }
                    }
                }
                return instFunc;
            }
            function _getProtoFunc(funcName, proto, currentDynProtoProxy) {
                var protoFunc = proto[funcName];
                if (protoFunc === currentDynProtoProxy) {
                    protoFunc = _getObjProto(proto)[funcName];
                }
                if (typeof protoFunc !== strFunction) {
                    _throwTypeError("[" + funcName + "] is not a " + strFunction);
                }
                return protoFunc;
            }
            function _populatePrototype(proto, className, target, baseInstFuncs, setInstanceFunc) {
                function _createDynamicPrototype(proto, funcName) {
                    var dynProtoProxy = function () {
                        var instFunc = _getInstFunc(this, funcName, proto, dynProtoProxy) || _getProtoFunc(funcName, proto, dynProtoProxy);
                        return instFunc.apply(this, arguments);
                    };
                    dynProtoProxy[DynProxyTag] = 1;
                    return dynProtoProxy;
                }
                if (!_isObjectOrArrayPrototype(proto)) {
                    var instFuncTable = target[DynInstFuncTable] = target[DynInstFuncTable] || objCreate(null);
                    if (!_isObjectOrArrayPrototype(instFuncTable)) {
                        var instFuncs_1 = instFuncTable[className] = (instFuncTable[className] || objCreate(null));
                        if (instFuncTable[DynAllowInstChkTag] !== false) {
                            instFuncTable[DynAllowInstChkTag] = !!setInstanceFunc;
                        }
                        if (!_isObjectOrArrayPrototype(instFuncs_1)) {
                            _forEachProp(target, function (name) {
                                if (_isDynamicCandidate(target, name, false) && target[name] !== baseInstFuncs[name]) {
                                    instFuncs_1[name] = target[name];
                                    delete target[name];
                                    if (!objHasOwnProperty(proto, name) || (proto[name] && !proto[name][DynProxyTag])) {
                                        proto[name] = _createDynamicPrototype(proto, name);
                                    }
                                }
                            });
                        }
                    }
                }
            }
            function _checkPrototype(classProto, thisTarget) {
                if (_objGetPrototypeOf) {
                    var visited = [];
                    var thisProto = _getObjProto(thisTarget);
                    while (thisProto && !_isObjectArrayOrFunctionPrototype(thisProto) && !_hasVisited(visited, thisProto)) {
                        if (thisProto === classProto) {
                            return true;
                        }
                        visited.push(thisProto);
                        thisProto = _getObjProto(thisProto);
                    }
                    return false;
                }
                return true;
            }
            function _getObjName(target, unknownValue) {
                if (objHasOwnProperty(target, Prototype)) {
                    return target.name || unknownValue || UnknownValue;
                }
                return (((target || {})[Constructor]) || {}).name || unknownValue || UnknownValue;
            }
            function dynamicProto(theClass, target, delegateFunc, options) {
                if (!objHasOwnProperty(theClass, Prototype)) {
                    _throwTypeError("theClass is an invalid class definition.");
                }
                var classProto = theClass[Prototype];
                if (!_checkPrototype(classProto, target)) {
                    _throwTypeError("[" + _getObjName(theClass) + "] not in hierarchy of [" + _getObjName(target) + "]");
                }
                var className = null;
                if (objHasOwnProperty(classProto, DynClassName)) {
                    className = classProto[DynClassName];
                }
                else {
                    className = DynClassNamePrefix + _getObjName(theClass, "_") + "$" + _gblInst.n;
                    _gblInst.n++;
                    classProto[DynClassName] = className;
                }
                var perfOptions = dynamicProto[DynProtoDefaultOptions];
                var useBaseInst = !!perfOptions[strUseBaseInst];
                if (useBaseInst && options && options[strUseBaseInst] !== undefined) {
                    useBaseInst = !!options[strUseBaseInst];
                }
                var instFuncs = _getInstanceFuncs(target);
                var baseFuncs = _getBaseFuncs(classProto, target, instFuncs, useBaseInst);
                delegateFunc(target, baseFuncs);
                var setInstanceFunc = !!_objGetPrototypeOf && !!perfOptions[strSetInstFuncs];
                if (setInstanceFunc && options) {
                    setInstanceFunc = !!options[strSetInstFuncs];
                }
                _populatePrototype(classProto, className, target, instFuncs, setInstanceFunc !== false);
            }
            dynamicProto[DynProtoDefaultOptions] = _gblInst.o;

        })
    };
}));
//# sourceMappingURL=dynamicproto-js.js.map
