/*!
 * Microsoft Dynamic Proto Utility, 2.0.3
 * Copyright (c) Microsoft and contributors. All rights reserved.
 */
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;

export { dynamicProto as default };
//# sourceMappingURL=dynamicproto-js.js.map
