# Source: data/model/object-descriptor.js

    var Montage = require("core/core").Montage,
        PropertyDescriptor = require("data/model/property-descriptor").PropertyDescriptor;

    /**
     * Describes a type of object.
     * @deprecated
     * @class
     * @extends external:Montage
     */
    exports.ObjectDescriptor = Montage.specialize(/** @lends ObjectDescriptor.prototype */ {

        /**
         * Name of the type of object described by this descriptor.
         *
         * @type {string}
         */
        typeName: {
            value: undefined
        },

        /**
         * Prototype of objects of this type.
         *
         * @type {function}
         */
        objectPrototype: {
            value: Montage.prototype
        },

        /**
         * Descriptors of the properties of objects of this type, by property name.
         *
         * The returned map should not be modified.
         * [setPropertyDescriptor()]{@link ObjectDescriptor#setPropertyDescriptor}
         * and
         * [deletePropertyDescriptor()]{@link ObjectDescriptor#deletePropertyDescriptor}
         * should be used instead to modify the property descriptors.
         *
         * @type {Object.<string, PropertyDescriptor>}
         */
        propertyDescriptors: {
            get: function () {
                if (!this._propertyDescriptors) {
                    this._propertyDescriptors = {};
                }
                return this._propertyDescriptors;
            }
        },

        /**
         * Add or replace a property descriptor.
         *
         * @method
         * @argument {string} name                   - The name of the property.
         * @argument {PropertyDescriptor} descriptor - Describes the property.
         */
        setPropertyDescriptor: {
            value: function (name, descriptor) {
                this.propertyDescriptors[name] = descriptor;
            }
        },

        /**
         * Remove a property descriptor.
         *
         * @method
         * @argument {string} name - The name of the property whose descriptor
         *                           should be removed.
         */
        deletePropertyDescriptor: {
            value: function (name) {
                delete this.propertyDescriptors[name];
            }
        },

        /**
         * Create a property descriptor.
         *
         * This implementation creates a plain {@link PropertyDescriptor} instance.
         * Subclasses can override this to create property descriptors of a
         * type more appropriate for the subclass. Any such type should be a
         * subclass of {@link PropertyDescriptor}.
         *
         * @method
         * @returns {PropertyDescriptor} - The created property descriptor.
         */
        makePropertyDescriptor: {
            value: function () {
                return new PropertyDescriptor();
            }
        },

        /**
         * @private
         * @method
         * @argument {Object<string, string>} types
         */
        _setPropertyDescriptorsFromTypes: {
            value: function (types) {
                var i, descriptor, key,
                    keys = Object.keys(types);
                for (i = 0; (key = keys[i]); ++i) {
                    descriptor = this.makePropertyDescriptor();
                    this.setPropertyDescriptor(key, descriptor);
                }
            }
        },

        /**
         * @private
         * @method
         * @argument {Object} prototype
         */
        _setPropertyDescriptorsFromPrototype: {
            value: function (prototype) {
                var names, descriptor, i, n;
                for (; prototype !== Montage.prototype && prototype !== null; prototype = Object.getPrototypeOf(prototype)) {
                    names = Object.getOwnPropertyNames(prototype);
                    for (i = 0, n = names.length; i < n; i += 1) {
                        if (!this.propertyDescriptors[names[i]]) {
                            descriptor = this.makePropertyDescriptor();
                            this.setPropertyDescriptor(names[i], descriptor);
                        }
                    }
                }
            }
        }

    }, /** @lends ObjectDescriptor */ {

        /**
         * Generates a getter function that will create and cache an object
         * descriptor.
         *
         * @method
         * @argument {Object} exports         - A
         *                                      [Montage Require]{@link external:Require}
         *                                      exports object defining the
         *                                      constructor for the objects to
         *                                      describe. Usually this is `exports`.
         * @argument {string} constructorName - The name with which that constructor
         *                                      can be looked up in the exports.
         *                                      This will also be used as the
         *                                      created descriptor's type name.
         * @argument {Object<string, string>}
         *           [propertyTypes]          - The types of each of the described
         *                                      objects' properties, by property
         *                                      name. If this is not specified the
         *                                      property information will be derived
         *                                      from the properties of the objects'
         *                                      prototype.
         */
        getterFor: {
            value: function (exports, constructorName, propertyTypes) {
                // The returned getter function has to check
                // `this.hasOwnProperty("_TYPE")`, not just `this._TYPE`, because if
                // the class using the getter is a subclass of another class using a
                // similar getter `this._TYPE` will return the value of the the
                // superclass type instead of the desired subclass type.
                var self = this;
                return function () {
                    if (!this.hasOwnProperty("_TYPE")) {
                        this._TYPE = new self();
                        this._TYPE.typeName = constructorName;
                        this._TYPE.objectPrototype = exports[constructorName].prototype;
                        if (propertyTypes) {
                            this._TYPE._setPropertyDescriptorsFromTypes(propertyTypes);
                        } else {
                            this._TYPE._setPropertyDescriptorsFromPrototype(this._TYPE.objectPrototype);
                        }
                    }
                    return this._TYPE;
                };
            }
        }

    });