Source: core/enum.js

/**
 * @module montage/core/enum
 * @requires montage/core/core
 * @requires montage/core/logger
 */
var Montage = require("./core").Montage,
    logger = require("./logger").logger("enum");

/**
 * @class Enum
 * @extends Montage
 */
exports.Enum = Montage.specialize( /** @lends Enum# */ {

    _value: {
        value: 0
    },

    _members: {
        value: null
    },

    members: {
        get: function () {
            return this._members || (this._members = Object.keys(this));
        }
    },

    /**
     * @function
     * @returns itself
     */
    init : {
        value: function () {
            this._logErrorIfAlreadySeal();
            return this;
        }
    },

    /**
     * @function
     * @returns {Object} Object.seal(this)
     */
    initWithMembers : {
        value: function () {
            if (this._logErrorIfAlreadySeal()) {
                return this;
            }

            this._addMembers(arguments);

            return Object.seal(this);
        }
    },


    /**
     * @function
     * @param {Array.<string>} array of keys.
     * @param {Array} array of values.
     * @returns {Object} Object.seal(this)
     */
    initWithMembersAndValues : {
        value: function (members, values) {
            if (Array.isArray(members) && Array.isArray(values)) {
                if (members.length === values.length) {
                    if (this._logErrorIfAlreadySeal()) {
                        return this;
                    }

                    this._addMembers(members, values);

                } else {
                    throw new Error("the number of members must equal to the number of values");
                }
            }

            return Object.seal(this);
        }
    },


    /**
     * @function
     * @param {string} member The member to be added.
     * @param value
     */
    addMember : {
        value: function (member, value) {
            if (typeof this[member] === "undefined") {
                Object.defineProperty(this, member, {
                    writable: false,
                    configurable: false,
                    enumerable: true,
                    value: value !== void 0 && value !== null ? value : this._value++
                });
            }
        }
    },

    /**
     * @function
     * @returns {Object} this, but sealed
     */
    seal : {
        value: function () {
            if (!Object.isSealed(this)) {
                return Object.seal(this);
            }
        }
    },


    _logErrorIfAlreadySeal: {
        value: function () {
            if (Object.isSealed(this)) {
                logger.error(this, "Object is sealed");

                return true;
            }

            return false;
        }
    },

    _addMembers: {
        value: function (members, values) {
            var member, i, value;

            for (i = 0; typeof (member = members[i]) !== "undefined"; i++) {
                if (member !== null) {
                    if (values) {
                        value = values[i];

                        if (value === void 0 && value === null) {
                            throw new Error("A value of an enumeration cannot be null or undefined");
                        }
                    }

                    this.addMember(member, value);
                } else {
                    logger.error(this, "Member at index " + i + " is null");
                }
            }
        }
    }
});