# Source: core/bitfield.js

    /**
     * Defines the BitField class, that compactly stores multiple values as a short
     * series of bits.
     * @module montage/core/bitfield
     * @requires montage/core/core
     */

    var Montage = require("./core").Montage;

    /**
     * The BitField object compactly stores multiple values as a short series of
     * bits.
     * This implementation is limited to 32 fields.
     * @class BitField
     * @classdesc Compactly stores multiple values as a short series of bits.
     * @extends Montage
     */
    var BitField = exports.BitField = Montage.specialize( /** @lends BitField */ {

        /**
         * Creates a new BitField object containing the fields provided in the
         * propertyDescriptor parameter.
         * @function
         * @param {Object} propertyDescriptor An object containing one or more
         * property name/value pairs.
         * Each pair is added to the new BitField.
         * @returns {Object} A new BitField object that contains fields described
         * by the property descriptor.
         * @example
         * var bitField = new BitField();
         * bitField = new BitField().initWithDescriptor({
         *     likes_golf: {
         *         value: false
         *     },
         *     likes_basketball: {
         *         value: true
         *     },
         *     likes_baseball: {
         *         value: false
         *     },
         * });
         */
        initWithDescriptor: {
            enumerable: false,
            value: function (propertyDescriptor) {
                var fieldName;
                this.reset();
                for (fieldName in propertyDescriptor) {
                    if (propertyDescriptor.hasOwnProperty(fieldName)) {
                        this.addField(fieldName, propertyDescriptor[fieldName].value);
                    }
                }
                return this;
            }
        },

        /**
         * Adds a new field to a BitField instance.
         * @function
         * @param {string} aFieldName The name of the field to add.
         * @param {Mixed} defaultValue The new field's default value.
         */
        addField: {
            enumerable: false,
            value: function (aFieldName, defaultValue) {
                if (aFieldName in this) {
                    return;
                }
                if (this._fieldCount >= 32) {
                    throw "BitField 32 fields limit reached.";
                }
                //We try to recycle slots as limited to 32bits
                this._trueValue += (this._fields[aFieldName] = this._constantsToReuse.length ? this._constantsToReuse.shift() : (1 << this._fieldCount));
                Montage.defineProperty(this, aFieldName, {
                    enumerable: true,
                    get: function () {
                        return (this._value === this._trueValue);
                    },
                    set: function (value) {

                        if (value) {
                            this._value |= this._fields[aFieldName];
                        } else {
                            this._value &= ~ (this._fields[aFieldName]);
                        }

                        if (this.value) {
                            this.callDelegateMethod();
                        }
                    }
                });
                this._fieldCount++;
                if (!! defaultValue) {
                    this[aFieldName] = true;
                }
            }
        },

        _constantsToReuse: {
            enumerable: false,
            value: []
        },

        /**
         * Removes a field from the bitfield.
         * @function
         * @param {string} aFieldName The name of the field to remove.
         */
        removeField: {
            enumerable: false,
            value: function (aFieldName) {
                delete this[aFieldName];
                this._constantsToReuse.push(this._fields[aFieldName]);
                this._trueValue -= this._fields[aFieldName];
                delete this._fields[aFieldName];
            }
        },

        /**
         * The BitField object's delegate.
         * @type {Property}
         * @default null
         */
        delegate: {
            enumerable: false,
            value: null
        },

        /**
         * @function
         * @returns Nothing
         */
        callDelegateMethod: {
            value: function () {
                var delegateMethod;
                if (this.delegate && typeof (delegateMethod = this.delegate.bitFieldDidBecomeTrue) === "function") {
                    delegateMethod.call(this.delegate, this);
                }
            },
            enumerable: false
        },
        /**
         * @type {Function}
         * @default {number} 0
         */
        value: {
            enumerable: false,
            get: function () {
                return (this._value === this._trueValue);
            }
        },

        _fieldCount: {
            enumerable: false,
            value: 0
        },

        _value: {
            enumerable: false,
            value: 0
        },

        _trueValue: {
            enumerable: false,
            value: 0
        },

        /**
         * @function
         */
        reset: {
            enumerable: false,
            value: function () {
                this._value = 0x0;
            }
        },

        _fields: {
            enumerable: false,
            value: {}
        },

        /**
         * @function
         */
        toString: {
            value: function () {
                var fieldNames = this._fields,
                    i,
                    iField,
                    result = "";
                for (i = 0; (iField = fieldNames[i]); i++) {
                    result += iField + "[" + (this._value & fieldNames[iField]) + "], ";
                }
                return result;
            }
        }

    });