Source: common/util/check.js

/**
 * Wrapper around Meteor's [check](http://docs.meteor.com/#check).
 * You can call `check` directly, and access [Match](http://docs.meteor.com/#match)
 * as the argument to the pattern
 *
 * @name check
 * @namespace
 * @private
 */
define(["lib/meteor", "./log", "lib/underscore"], function(meteor, Log, _) {
    "use strict";

    var logger = Log("ArgumentChecker");

    var enabled = true;
    var warn = false;

    var check = function(arg, pattern) {
        if(!enabled) {
            return;
        }

        try {
            meteor.check.check(arg, pattern);
        }
        catch(e) {
            console.trace();
            if(warn) {
                logger.warn(e.message);
            }
            else {
                throw e.message;
            }
        }
    };

    check.Match = meteor.check.Match;

    // special-case patterns Meteor doesn't support
    check.Match.Element = check.Match.Where(function(el) {
        if(!(el instanceof Element)) {
            throw check.Match.Error("Expected Element");
        }
        return true;
    });

    check.Match.Elementish = check.Match.Where(function(el) {
        if(el === undefined) {
            throw check.Match.Error("Expected CSS selector, DOM element, or jQuery object; got undefined");
        }
        if(!((el instanceof Element) || (typeof (el.jquery) === "string") || (typeof el === "string"))) {
            throw check.Match.Error("Expected CSS selector, DOM element, or jQuery object");
        }
        return true;
    });

    check.Match.Serializable = check.Match.Where(function(o) {
        if((o === undefined) || !_.isEqual(JSON.parse(JSON.stringify(o)), o)) {
            throw check.Match.Error("Found non-JSON-serializable value");
        }
        return true;
    });

    check.Match.Pair = function(type) {
        return check.Match.Where(function(o) {
            if(o.length !== 2) {
                throw check.Match.Error("Expected pair of values, got array of length " + o.length);
            }

            try {
                check(o, [type]);
            }
            catch(e) {
                throw check.Match.Error("Expected pair of " + type + ", but type was incorrect");
            }

            return true;
        });
    };

    check.Match.Machine = check.Match.Where(function(o) {
        if(!o._isLensMachine) {
            throw check.Match.Error("Expected Machine");
        }
        return true;
    });

    check.Match.Enum = function(values) {
        return check.Match.Where(function(o) {
            var matches = _.any(values, function(value) {
                return o === value;
            });

            if(matches) {
                return true;
            }
            else {
                throw check.Match.Error("Expected one of [" + values.join() + "], got " + o);
            }
        });
    };

    check.Match.Integer = check.Match.Where(function(o) {
        var matches = typeof o === "number" && o % 1 === 0;

        if(matches) {
            return true;
        }
        else {
            throw check.Match.Error("Expected an integer, got " + o);
        }
    });


    /**
     * Turns off run-time argument checking.
     */
    Lens.disableArgChecking = function() {
        enabled = false;
    };

    /**
     * Turns on run-time argument checking. Argument checking is on by default,
     * so you only need to call this if you want to re-enable argument checking.
     */
    Lens.enableArgChecking = function() {
        enabled = true;
    };

    /**
     * By default, Lens's argument checking throws an error. Calling this will
     * make it print a warning to the console instead.
     */
    Lens.warnForArgChecking = function() {
        warn = true;
    };

    return check;
});