# Source: core/uuid.js

    /* <notice>
     Code from node-uuid: https://github.com/broofa/node-uuid/raw/master/uuid.js
     MIT license https://github.com/broofa/node-uuid/blob/master/LICENSE.md
     </notice> */

    /**
     * @module montage/core/uuid
    */

    /**
     * @class Uuid
     * @extends Montage
     */
    var Montage = require("core/core").Montage,
        CHARS = '0123456789ABCDEF'.split(''),
        PROTO = "__proto__",
        VALUE = "value",
        FORMAT = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.split('');

    function generate() {
        var c = CHARS, id = FORMAT, r;

        id[0] = c[(r = Math.random() * 0x100000000) & 0xf];
        id[1] = c[(r >>>= 4) & 0xf];
        id[2] = c[(r >>>= 4) & 0xf];
        id[3] = c[(r >>>= 4) & 0xf];
        id[4] = c[(r >>>= 4) & 0xf];
        id[5] = c[(r >>>= 4) & 0xf];
        id[6] = c[(r >>>= 4) & 0xf];
        id[7] = c[(r >>>= 4) & 0xf];

        id[9] = c[(r = Math.random() * 0x100000000) & 0xf];
        id[10] = c[(r >>>= 4) & 0xf];
        id[11] = c[(r >>>= 4) & 0xf];
        id[12] = c[(r >>>= 4) & 0xf];
        id[15] = c[(r >>>= 4) & 0xf];
        id[16] = c[(r >>>= 4) & 0xf];
        id[17] = c[(r >>>= 4) & 0xf];

        id[19] = c[(r = Math.random() * 0x100000000) & 0x3 | 0x8];
        id[20] = c[(r >>>= 4) & 0xf];
        id[21] = c[(r >>>= 4) & 0xf];
        id[22] = c[(r >>>= 4) & 0xf];
        id[24] = c[(r >>>= 4) & 0xf];
        id[25] = c[(r >>>= 4) & 0xf];
        id[26] = c[(r >>>= 4) & 0xf];
        id[27] = c[(r >>>= 4) & 0xf];

        id[28] = c[(r = Math.random() * 0x100000000) & 0xf];
        id[29] = c[(r >>>= 4) & 0xf];
        id[30] = c[(r >>>= 4) & 0xf];
        id[31] = c[(r >>>= 4) & 0xf];
        id[32] = c[(r >>>= 4) & 0xf];
        id[33] = c[(r >>>= 4) & 0xf];
        id[34] = c[(r >>>= 4) & 0xf];
        id[35] = c[(r >>>= 4) & 0xf];

        return id.join('');
    }

    exports.generate = generate;

    var Uuid = exports.Uuid = Object.create(Object.prototype, /** @lends Uuid# */ {
        /**
         * Returns a univerally unique ID (UUID).
         * @function Uuid.generate
         * @returns {string} The UUID.
         */
        generate: {
            enumerable: false,
            value: generate
        }
    });

    // TODO figure out why this code only works in this module.  Attempts to move
    // it to core/extras/object resulted in _uuid becoming enumerable and tests
    // breaking. - @kriskowal

    // var UUID = require("./uuid");

    // HACK: This is to fix an IE10 bug where a getter on the window prototype chain
    // gets some kind of proxy Window object which cannot have properties defined
    // on it, instead of the `window` itself. Adding the uuid directly to the
    // window removes the needs to call the getter.
    // if (typeof window !== "undefined") {
    //     window.uuid = UUID.generate();
    // }
    var uuidGetGenerator = function () {

        var uuid = generate(),
            info = Montage.getInfoForObject(this);
        try {
            if (info !== null && info.isInstance === false) {
                this._uuid = uuid;
                Object.defineProperty(this, "uuid", {
                    get: function () {
                        if (this.hasOwnProperty("uuid")) {
                            // we are calling uuid on the prototype
                            return this._uuid;
                        } else {
                            // we are calling uuid on instance of this prototype
                            return uuidGetGenerator.call(this);
                        }
                    }
                });
            } else {
                //This is needed to workaround some bugs in Safari where re-defining uuid doesn't work for DOMWindow.
                if (info.isInstance) {
                    Object.defineProperty(this, "uuid", {
                        configurable: true,
                        enumerable: false,
                        writable: false,
                        value: uuid
                    });
                }
                //This is really because re-defining the property on DOMWindow actually doesn't work, so the original property with the getter is still there and return this._uuid if there.
                if (this instanceof Element || !info.isInstance || !(VALUE in (Object.getOwnPropertyDescriptor(this, "uuid")||{})) || !(PROTO in this /* lame way to detect IE */)) {
                    //This is needed to workaround some bugs in Safari where re-defining uuid doesn't work for DOMWindow.
                    this._uuid = uuid;
                }
            }
        } catch(e) {
            // NOTE Safari (as of Version 5.0.2 (6533.18.5, r78685)
            // doesn't seem to allow redefining an existing property on a DOM Element
            // Still want to redefine the property where possible for speed
        }

        // NOTE Safari (as of Version 6.1 8537.71) has a bug related to ES5
        // property values. In some situations, even when the uuid has already
        // been defined as a property value, accessing the uuid of an object can
        // make it go through the defaultUuidGet as if the property descriptor
        // was still the original one. When that happens, a new uuid is created
        // for that object. To avoid this, we always make sure that the object
        // has a _uuid that will be looked up at defaultUuidGet() before
        // generating a new one. This mechanism was created to work around an
        // issue with Safari that didn't allow redefining property descriptors
        // in DOM elements.
        this._uuid = uuid;

        return uuid;
    };

    var defaultUuidGet = function defaultUuidGet() {
        //return this._uuid || (this._uuid = uuidGetGenerator.call(this));
        return ((Object.prototype.hasOwnProperty.call(this, "_uuid") &&  this._uuid) ? this._uuid : uuidGetGenerator.call(this));
    };

    Montage.defineUuidProperty = function(object) {
        /**
            @private
        */
        Object.defineProperty(object, "_uuid", {
            enumerable: false,
            value: void 0,
            writable: true
        });

        /**
            Contains an object's unique ID.
            @member external:Object#uuid
            @default null
        */
        Object.defineProperty(object, "uuid", {
            configurable: true,
            get: defaultUuidGet,
            set: Function.noop,
            enumerable: false
        });
    };