# Source: core/deprecate.js

    /* global console */
    var Montage = require("./core").Montage;
        Map = require("collections/map");

    var deprecatedFeaturesOnceMap = new Map();

    function generateDeprecatedKey(name, alternative) {
        return alternative ? name + "_" + alternative : name;
    }

    /**
     * @module montage/core/deprecate
     */

    /**
     * Prints out a deprecation warning to the console.warn with the format:
     * `name` is deprecated, use `alternative` instead.
     * It can also print out a stack trace with the line numbers.
     *
     * @param {String} name - Name of the thing that is deprecated.
     * @param {String} alternative - Name of alternative that should be used instead.
     * @param {Number} [stackTraceLimit] - depth of the stack trace to print out. Set to falsy value to disable stack.
     */
    var deprecationWarning = exports.deprecationWarning = function deprecationWarning(name, alternative, stackTraceLimit) {
        stackTraceLimit = stackTraceLimit === true ? 2 : stackTraceLimit;
        var stackTraceLimitOrigin;
        if (stackTraceLimit) {
            stackTraceLimitOrigin = Error.stackTraceLimit;
            Error.stackTraceLimit = stackTraceLimit;
        }
        if (typeof console !== "undefined" && typeof console.warn === "function") {
            var stack = (stackTraceLimit ? new Error("").stack : "") ;
            if(alternative) {
                console.warn(name + " is deprecated, use " + alternative + " instead.", stack);
            } else {
                //name is a complete message
                console.warn(name, stack);
            }
        }
        if (stackTraceLimit) {
            Error.stackTraceLimit = stackTraceLimitOrigin;
        }
    };

    /**
     *
     * Call deprecationWarning function only once.
     *
     * @param {String} name - Name of the thing that is deprecated.
     * @param {String} alternative - Name of alternative that should be used instead.
     * @param {Number} [stackTraceLimit] - depth of the stack trace to print out. Set to falsy value to disable stack.
     */
    exports.deprecationWarningOnce = function deprecationWarningOnce(name, alternative, stackTraceLimit) {
        var key = generateDeprecatedKey(name, alternative);
        if (!deprecatedFeaturesOnceMap.has(key)) {
            exports.deprecationWarning(name, alternative, stackTraceLimit);
            deprecatedFeaturesOnceMap.set(key, true);
        }
    };

    /**
     * Provides a function that can replace a method that has been deprecated.
     * Prints out a deprecation warning to the console.warn with the format:
     * `name` is deprecated, use `alternative` instead.
     * It will also print out a stack trace with the line numbers.
     *
     * @param {Object} scope - The object that will be used as the `this` when the `deprecatedFunction` is applied.
     * @param {Function} deprecatedFunction - The function object that is deprecated.
     * @param {String} name - Name of the method that is deprecated.
     * @param {String} alternative - Name of alternative method that should be used instead.
     *
     * @returns {Function} deprecationWrapper
     */
    exports.deprecateMethod = function deprecate(scope, deprecatedFunction, name, alternative) {
        var deprecationWrapper = function () {
            // stackTraceLimit = 3 // deprecationWarning + deprecate + caller of the deprecated method
            deprecationWarning(name, alternative, 3);
            return deprecatedFunction.apply(scope ? scope : this, arguments);
        };
        deprecationWrapper.deprecatedFunction = deprecatedFunction;
        return deprecationWrapper;
    };

    /**
     * To call a function immediately and log a deprecation warning
     *
     * @param scope
     * @param callback
     * @param name
     * @param alternative
     * @returns {*}
     */
    exports.callDeprecatedFunction = function (scope, callback, name, alternative/*, ...args */) {
        var depth = Error.stackTraceLimit,
            scopeName,
            args;

        Error.stackTraceLimit = 2;
        if (typeof console !== "undefined" && typeof console.warn === "function") {
            scopeName = Montage.getInfoForObject(scope).objectName;

            if (alternative) {
                console.warn(name + " is deprecated, use " + alternative + " instead.", scopeName);
            } else {
                // name is a complete message
                console.warn(name, scopeName);
            }

        }
        Error.stackTraceLimit = depth;
        args = Array.prototype.slice.call(arguments, 4);
        return callback.apply(scope ? scope : this, args);
    };