var inherit = require('./inherit');
var object = require('./object');
/**
* Create a new instance of class sceneObject, which extends the object's
* event handling with a tree-based event propagation.
*
* @class
* @alias geo.sceneObject
* @extends geo.object
* @param {object} arg Options for the object.
* @returns {geo.sceneObject}
*/
var sceneObject = function (arg) {
'use strict';
if (!(this instanceof sceneObject)) {
return new sceneObject();
}
object.call(this, arg);
var m_this = this,
m_parent = null,
m_children = [],
s_exit = this._exit,
s_trigger = this.geoTrigger,
s_addPromise = this.addPromise,
s_removePromise = this.removePromise;
/**
* Add the promise here and also propagate up the scene tree.
*
* @param {Promise} promise A promise object.
* @returns {this}
*/
this.addPromise = function (promise) {
if (m_parent) {
m_parent.addPromise(promise);
}
s_addPromise(promise);
return m_this;
};
/**
* Remove the promise here and also propagate up the scene tree.
*
* @param {Promise} promise A promise object.
* @returns {this}
*/
this.removePromise = function (promise) {
if (m_parent) {
m_parent.removePromise(promise);
}
s_removePromise(promise);
return m_this;
};
/**
* Get/set parent of the object.
*
* @param {geo.sceneObject} [arg] The new parent or `undefined` to get the
* current parent.
* @returns {this|geo.sceneObject}
*/
this.parent = function (arg) {
if (arg === undefined) {
return m_parent;
}
m_parent = arg;
return m_this;
};
/**
* Add a child (or an array of children) to the object.
*
* @param {geo.object|geo.object[]} child A child object or array of child
* objects.
* @returns {this}
*/
this.addChild = function (child) {
if (Array.isArray(child)) {
child.forEach(m_this.addChild);
return m_this;
}
child.parent(m_this);
m_children.push(child);
return m_this;
};
/**
* Remove a child (or array of children) from the object.
*
* @param {geo.object|geo.object[]} child A child object or array of child
* objects.
* @returns {this}
*/
this.removeChild = function (child) {
if (Array.isArray(child)) {
child.forEach(m_this.removeChild);
return m_this;
}
m_children = m_children.filter(function (c) { return c !== child; });
return m_this;
};
/**
* Get an array of the child objects.
*
* @returns {geo.object[]} A copy of the array of child objects.
*/
this.children = function () {
return m_children.slice();
};
/**
* Force redraw of a scene object, to be implemented by subclasses.
* Base class just calls draw of child objects.
*
* @param {object} arg Options to pass to the child draw functions.
* @returns {this}
*/
this.draw = function (arg) {
m_this.children().forEach(function (child) {
child.draw(arg);
});
return m_this;
};
/**
* Trigger an event (or events) on this object and call all handlers.
*
* @param {string} event The event to trigger.
* @param {object} args Arbitrary argument to pass to the handler.
* @param {boolean} [childrenOnly] If truthy, only propagate down the tree.
* @returns {this}
*/
this.geoTrigger = function (event, args, childrenOnly) {
var geoArgs;
args = args || {};
geoArgs = args.geo || {};
args.geo = geoArgs;
// stop propagation if requested by the handler
if (geoArgs.stopPropagation) {
return m_this;
}
// If the event was not triggered by the parent, just propagate up the tree
if (!childrenOnly && m_parent && geoArgs._triggeredBy !== m_parent) {
geoArgs._triggeredBy = m_this;
m_parent.geoTrigger(event, args);
return m_this;
}
// call the object's own handlers
s_trigger.call(m_this, event, args);
// stop propagation if requested by the handler
if (geoArgs.stopPropagation) {
return m_this;
}
// trigger the event on the children
m_children.forEach(function (child) {
if (child.geoTrigger) {
geoArgs._triggeredBy = m_this;
child.geoTrigger(event, args);
}
});
return m_this;
};
/**
* Free all resources and destroy the object.
*/
this._exit = function () {
m_children = [];
m_parent = null;
s_exit();
};
return this;
};
inherit(sceneObject, object);
module.exports = sceneObject;