# Source: core/target.js

    var Montage = require("./core").Montage,
        defaultEventManager = require("./event/event-manager").defaultEventManager,
        MutableEvent = require("./event/mutable-event").MutableEvent;

    /**
     * A Target is any object that can be a candidate for dispatching and receiving
     * events throughout what is typically considered the "component tree" of a
     * Montage application.
     *
     * @class Target
     * @extends Montage
     */
    exports.Target = Montage.specialize( /** @lends Target.prototype */{
        /**
         * Whether or not this target can accept user focus and become the
         * activeTarget This matches up with the `document.activeElement` property
         * purpose-wise; Events from components that should be dispatched as
         * logically occurring at the point of user focus should be dispatched at
         * the activeTarget
         *
         * By default a target does not accept this responsibility.
         *
         * @type {boolean}
         * @default false
         */
        acceptsActiveTarget: {
            serializable: false,
            value: false
        },

        /**
         * Whether or not this is the activeTarget
         *
         * This is a getter and is not bindable. Bind to
         * `defaultEventManager.activeTarget == this`.
         *
         * @type {boolean}
         * @readonly
         */
        isActiveTarget: {
            get: function () {
                return this === defaultEventManager.activeTarget;
            }
        },

        /**
         * Called prior to this target becoming the activeTarget
         * @function
         * @param {Target} oldTarget the current activeTarget
         */
        willBecomeActiveTarget: {
            value: Function.noop
        },

        /**
         * Called after to this target became the activeTarget
         * @function
         */
        didBecomeActiveTarget: {
            value: Function.noop
        },

        /**
         * Ask this target to surrender its activeTarget status.
         * @function
         * @param {Target} newTarget the Target that is about to become the
         * `activeTarget`
         * @returns {boolean} Whether or not to surrender activeTarget status
         */
        surrendersActiveTarget: {
            value: function (newTarget) {
                return true;
            }
        },

        /**
         * Which target to distribute an event after this when distributing events
         * throughout a graph of targets.
         * @property {boolean} serializable
         * @property {Component} value
         */
        nextTarget: {
            serializable: false,
            value: null
        },

        /**
         * Dispatches the specified event with this target
         * as the event's proximal target
         * @function
         * @param {Event} event The event object to dispatch
         */
        dispatchEvent: {
            value: function (event) {
                var targettedEvent = (event instanceof MutableEvent) ? event : MutableEvent.fromEvent(event);
                targettedEvent.target = this;
                defaultEventManager.handleEvent(targettedEvent);
                return !event.defaultPrevented;
            }
        },

        /**
         * Creates and dispatches an event with the specified properties with this
         * target as the event's proximal target
         * @function
         * @param {string} type The type of the event to dispatch
         * @param {boolean} canBubble Whether or not the event can bubble
         * @param {boolean} cancelable Whether or not the event can be cancelled
         * @param {Object} detail The optional detail object of the event
         */
        dispatchEventNamed: {
            value: function (type, canBubble, cancelable, detail) {
                var event = MutableEvent.fromType(type, canBubble, cancelable, detail);
                event.target = this;
                defaultEventManager.handleEvent(event);

                return !event.defaultPrevented;
            }
        },

        /**
         * Adds an event listener to the object.
         * @function
         * @param {string} type The event type to listen for.
         * @param {object | function} listener The listener object or function.
         * @param {boolean} useCapture Specifies whether to listen for the event during the bubble or capture phases.
         */
        addEventListener: {
            value: function addEventListener(type, listener, useCapture) {
                if (listener) {
                    defaultEventManager.registerEventListener(this, type, listener, useCapture);
                }
            }
        },

        /**
         * Removes an event listener from the object.
         * @function
         * @param {string} type The event type.
         * @param {object | function} listener The listener object or function.
         * @param {boolean} useCapture The phase of the event listener.
         */
        removeEventListener: {
            value: function removeEventListener(type, listener, useCapture) {
                if (listener) {
                    defaultEventManager.unregisterEventListener(this, type, listener, useCapture);
                }
            }
        },

        /**
         * Load a Composer
         * @function
         * @param {Composer} composer
         */
        loadComposer: {
            value: function (composer) {
                if (composer && !composer._isLoaded) {
                    composer._resolveDefaults();
                    composer.load();
                    composer._isLoaded = true;
                }
            }
        },

        /**
         * Unload a Composer
         * @function
         * @param {Composer} composer
         */
        unloadComposer: {
            value: function (composer) {
                if (composer && composer._isLoaded) {
                    composer.unload();
                    composer._isLoaded = false;
                }
            }
        }

    });