# Source: core/gate.js

    /**
     * @module montage/core/gate
     * @requires montage/core/core
     * @requires montage/core/logger
     */
    var Montage = require("./core").Montage,
        logger = require("./logger").logger("gate"),
        Map = require("collections/map");

    /**
     * @class Gate
     * @extends Montage
     */
    var Gate = exports.Gate = Montage.specialize(/** @lends Gate.prototype # */ {

        /**
         * @function
         * @returns {Gate} A new Gate instance.
         */
        init: {
            enumerable: false,
            value: function () {
                this.reset();
                return this;
            }
        },

        /**
         * @function
         * @param {string} delegate The delegate to be initialized.
         * @returns itself
        */
        initWithDelegate: {
            enumerable: false,
            value: function (delegate) {
                this.reset();
                this.delegate = delegate;
                return this;
            }
        },

        /**
         * @function
         * @param {string} propertyDescriptor The propertyDescriptor to be initialized.
         * @returns itself
         */
        initWithDescriptor: {
            enumerable: false,
            value: function (propertyDescriptor) {
                var fieldName;
                this.reset();
                for (fieldName in propertyDescriptor) {
                    if (propertyDescriptor.hasOwnProperty(fieldName)) {
                        this.setField(fieldName, propertyDescriptor[fieldName].value);
                    }
                }
                return this;
            }
        },

        /**
         * @type {Property}
         * @default {number} 0
         */
        count: {
            value: 0
        },

        /**
         * @type {Property}
         * @default {string} null
         */
        table: {
            value: null
        },

        /**
         * @function
         * @param {Array} aFieldName The aFieldName array.
         * @returns !table or table[aFieldName]
         */
        getField: {
            enumerable: false,
            value: function (aFieldName) {
                var table = this.table;
                return !table || table[aFieldName];
            }
        },

        /**
         * @function
         * @param {Array} aFieldName The aFieldName array.
         * @param {number} value The count on the array.
         */
        setField: {
            enumerable: false,
            value: function (aFieldName, value) {
                var table = this.table || (this.table = new Map()),
                    fieldValue,
                    oldCount = this.count;

                fieldValue = table[aFieldName];

                if (typeof fieldValue === "undefined" && !value) {
                    // new field
                    this.count++;
                } else if (typeof fieldValue !== "undefined" && fieldValue !== value) {
                    if (value) {
                        this.count--;
                    } else {
                        this.count++;
                    }
                } else if (value && logger.isDebug) {
                    logger.debug(this, aFieldName + " was not set before.");
                }
                table[aFieldName] = !!value;
                if (this.count === 0 && oldCount > 0) {
                    this.callDelegateMethod(true);
                } else if (oldCount === 0 && this.count > 0) {
                    this.callDelegateMethod(false);
                }
            }
        },

        /**
         * @function
         * @param {Array} aFieldName The aFieldName array to be removed.
         */
        removeField: {
            enumerable: false,
            value: function (aFieldName) {
                var table = this.table, fieldValue = table[aFieldName];
                if (typeof fieldValue !== "undefined" && !fieldValue) {
                    // if the value was false decrement the count
                    this.count--;
                }
                delete table[aFieldName];
            }
        },

        /**
         * @type {Property}
         * @default {string} null
         */
        delegate: {
            enumerable: false,
            value: null
        },

        /**
         * @function
         * @param {number} value The value to be called.
         */
        callDelegateMethod: {
            value: function (value) {
                var delegateMethod;
                if (this.delegate && typeof (delegateMethod = this.delegate["gateDidBecome" + (value ? "True" : "False")]) === "function") {
                    delegateMethod.call(this.delegate, this);
                }
            },
            enumerable: false
        },

        /**
         * @type {Function}
         * @returns this.count === 0
         */
        value: {
            enumerable: false,
            get: function () {
                return this.count === 0;
            }
        },

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

        /**
         * @function
         * @returns {string} result
         */
        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;
            }
        }

    });