package aerys.minko.scene.node
{
	import aerys.minko.ns.minko_scene;
	import aerys.minko.render.shader.part.phong.attenuation.MatrixShadowMapAttenuationShaderPart;
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.controller.IRebindableController;
	import aerys.minko.scene.controller.TransformController;
	import aerys.minko.type.Signal;
	import aerys.minko.type.clone.CloneOptions;
	import aerys.minko.type.clone.ControllerCloneAction;
	import aerys.minko.type.math.Matrix4x4;
	import aerys.minko.type.math.Vector4;

	import flash.utils.Dictionary;
	import flash.utils.getQualifiedClassName;
	import flash.utils.setTimeout;

	use namespace minko_scene;

	/**
	 * The base class to extend in order to create new scene node types.
	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public class AbstractSceneNode implements ISceneNode
	{
		private static var _id	    	    	: uint;

		private var _name	    	    		: String;
		private var _root	        			: ISceneNode;
		private var _parent	        			: Group;

		private var _transform			        : Matrix4x4;

		private var _controllers		        : Vector.<AbstractController>;
        private var _transformController        : TransformController;

		private var _added				        : Signal;
		private var _removed			        : Signal;
		private var _controllerAdded	        : Signal;
		private var _controllerRemoved	        : Signal;
        private var _visibilityChanged          : Signal;
        private var _computedVisibilityChanged  : Signal;
		private var _localToWorldChanged		: Signal;

        final public function get x() : Number
		{
			return _transform.translationX;
		}
        final public function set x(value : Number) : void
		{
			_transform.translationX = value;
		}

        final public function get y() : Number
		{
			return _transform.translationX;
		}
        final public function set y(value : Number) : void
		{
			_transform.translationY = value;
		}

        final public function get z() : Number
		{
			return _transform.translationX;
		}
        final public function set z(value : Number) : void
		{
			_transform.translationZ = value;
		}

        final public function get rotationX() : Number
		{
			return _transform.rotationX;
		}
        final public function set rotationX(value : Number) : void
		{
			_transform.rotationX = value;
		}

        final public function get rotationY() : Number
		{
			return _transform.rotationY;
		}
        final public function set rotationY(value : Number) : void
		{
			_transform.rotationY = value;
		}

        final public function get rotationZ() : Number
		{
			return _transform.rotationZ;
		}
        final public function set rotationZ(value : Number) : void
		{
			_transform.rotationZ = value;
		}

        final public function get scaleX() : Number
		{
			return _transform.scaleX;
		}
        final public function set scaleX(value : Number) : void
		{
			_transform.scaleX = value;
		}

        final public function get scaleY() : Number
		{
			return _transform.scaleY;
		}
        final public function set scaleY(value : Number) : void
		{
			_transform.scaleY = value;
		}

        final public function get scaleZ() : Number
		{
			return _transform.scaleZ;
		}
        final public function set scaleZ(value : Number) : void
		{
			_transform.scaleZ = value;
		}

        public function get name() : String
		{
			return _name;
		}
        public function set name(value : String) : void
		{
			_name = value;
		}

        final public function get parent() : Group
		{
			return _parent;
		}
        final public function set parent(value : Group) : void
		{
			if (value == _parent)
				return ;

			// remove child
			if (_parent)
			{
				var oldParent : Group = _parent;

				oldParent._children.splice(oldParent.getChildIndex(this), 1);

				parent._numChildren--;
				_parent = null;
				_removed.execute(this, oldParent);
				oldParent.descendantRemoved.execute(oldParent, this);
			}

			// set parent
			_parent = value;

			// add child
			if (_parent)
			{
				_parent._children[_parent.numChildren] = this;
				_parent._numChildren++;
				_added.execute(this, _parent);
				_parent.descendantAdded.execute(_parent, this);
			}
		}

        final public function get scene() : Scene
        {
            return _root as Scene;
        }

        final public function get root() : ISceneNode
		{
			return _root;
		}

        final public function get transform() : Matrix4x4
		{
			return _transform;
		}

        final public function get added() : Signal
		{
			return _added;
		}

        final public function get removed() : Signal
		{
			return _removed;
		}

		public function get numControllers() : uint
		{
			return _controllers.length;
		}

		public function get controllerAdded() : Signal
		{
			return _controllerAdded;
		}

		public function get controllerRemoved() : Signal
		{
			return _controllerRemoved;
		}

		public function get localToWorldTransformChanged() : Signal
		{
			return _localToWorldChanged;
		}

		public function AbstractSceneNode()
		{
			initialize();
		}

		protected function initialize() : void
		{
			_name = getDefaultSceneName(this);
			_transform = new Matrix4x4();
			_controllers = new <AbstractController>[];
			_root = this;

			initializeSignals();
			initializeSignalHandlers();
			initializeContollers();
			initializeDataProviders();
		}

		protected function initializeSignals() : void
		{
			_added = new Signal('AbstractSceneNode.added');
			_removed = new Signal('AbstractSceneNode.removed');
			_controllerAdded = new Signal('AbstractSceneNode.controllerAdded');
			_controllerRemoved = new Signal('AbstractSceneNode.controllerRemoved');
			_visibilityChanged = new Signal('AbstractSceneNode.visibilityChanged');
			_computedVisibilityChanged = new Signal('AbstractSceneNode.computedVisibilityChanged');
			_localToWorldChanged = new Signal('AbstractSceneNode.localToWorldChanged');
		}

		protected function initializeSignalHandlers() : void
		{
			_added.add(addedHandler);
			_removed.add(removedHandler);
		}

		protected function initializeContollers() : void
		{
            _transformController = new TransformController();
			addController(_transformController);
		}

		protected function initializeDataProviders() : void
		{
			// nothing
		}

		private function addedHandler(child : ISceneNode, ancestor : Group) : void
		{
           _root = _parent ? _parent.root : this;
		}

		private function removedHandler(child : ISceneNode, ancestor : Group) : void
		{
			_root = _parent ? _parent.root : this;
		}

		public function addController(controller : AbstractController) : ISceneNode
		{
			_controllers.push(controller);

			controller.addTarget(this);
			_controllerAdded.execute(this, controller);

			return this;
		}

		public function removeController(controller : AbstractController) : ISceneNode
		{
			var numControllers	: uint  = _controllers.length - 1;
            var controllerId    : int   = _controllers.indexOf(controller);

            if (controllerId < 0)
                throw new Error('The controller is not on the node.');

			_controllers[controllerId] = _controllers[numControllers];
			_controllers.length = numControllers;

			controller.removeTarget(this);
			_controllerRemoved.execute(this, controller);

			return this;
		}

		public function getController(index : uint) : AbstractController
		{
			return _controllers[index];
		}

		public function getControllersByType(type			: Class,
											 controllers	: Vector.<AbstractController> = null) : Vector.<AbstractController>
		{
			controllers ||= new Vector.<AbstractController>();

			var nbControllers : uint = numControllers;

			for (var i : int = 0; i < nbControllers; ++i)
			{
				var ctrl 	: AbstractController	= getController(i);

				if (ctrl is type)
					controllers.push(ctrl);
			}

			return controllers;
		}

		public static function getDefaultSceneName(scene : ISceneNode) : String
		{
			var className : String = getQualifiedClassName(scene);

			return className.substr(className.lastIndexOf(':') + 1)
				   + '_' + (++_id);
		}

		minko_scene function cloneNode() : AbstractSceneNode
		{
			throw new Error('Must be overriden');
		}

		public final function clone(cloneOptions : CloneOptions = null) : ISceneNode
		{
			cloneOptions ||= CloneOptions.defaultOptions;

			// fill up 2 dics with all nodes and controllers
			var nodeMap			: Dictionary = new Dictionary();
			var controllerMap	: Dictionary = new Dictionary();
			listItems(cloneNode(), nodeMap, controllerMap);

			// clone controllers with respect with instructions
			cloneControllers(controllerMap, cloneOptions);

			// rebind all controller dependencies.
			rebindControllerDependencies(controllerMap, nodeMap, cloneOptions);

			// add cloned/rebinded/original controllers to clones
			for (var objNode : Object in nodeMap)
			{
				var node			: AbstractSceneNode = AbstractSceneNode(objNode);
				var numControllers	: uint = node.numControllers;

				for (var controllerId : uint = 0; controllerId < numControllers; ++controllerId)
				{
					var controller : AbstractController = controllerMap[node.getController(controllerId)];
					if (controller != null)
						nodeMap[node].addController(controller);
				}
			}

			return nodeMap[this];
		}

		minko_scene function getLocalToWorldTransformUnsafe(forceUpdate : Boolean = false) : Matrix4x4
		{
			return _transformController.getLocalToWorldTransform(this, forceUpdate);
		}

        minko_scene function getWorldToLocalTransformUnsafe(forceUpdate : Boolean = false) : Matrix4x4
        {
            return _transformController.getWorldToLocalTransform(this, forceUpdate);
        }

		public function getLocalToWorldTransform(forceUpdate 	: Boolean 	= false,
												 output 		: Matrix4x4 = null) : Matrix4x4
		{
			output ||= new Matrix4x4();
			output.copyFrom(_transformController.getLocalToWorldTransform(this, forceUpdate));

			return output;
		}

		public function getWorldToLocalTransform(forceUpdate 	: Boolean 	= false,
												 output			: Matrix4x4 = null) : Matrix4x4
		{
            output ||= new Matrix4x4();
            output.copyFrom(_transformController.getWorldToLocalTransform(this, forceUpdate));

			return output;
		}

		public function localToWorld(inputVector 						: Vector4,
									 outputVector 						: Vector4 	= null,
                                     skipTranslation                    : Boolean   = false,
									 forceLocalToWorldTransformUpdate	: Boolean	= false) : Vector4
		{
			var localToWorld : Matrix4x4 = getLocalToWorldTransformUnsafe(
				forceLocalToWorldTransformUpdate
			);

			return skipTranslation
                ? localToWorld.deltaTransformVector(inputVector, outputVector)
                : localToWorld.transformVector(inputVector, outputVector);
		}

        public function worldToLocal(inputVector						: Vector4,
                                     outputVector						: Vector4 	= null,
                                     skipTranslation                    : Boolean   = false,
                                     forceWorldToLocalTransformUpdate	: Boolean	= false) : Vector4
        {
            var worldToLocal : Matrix4x4 = getWorldToLocalTransformUnsafe(
                forceWorldToLocalTransformUpdate
            );

            return skipTranslation
                ? worldToLocal.deltaTransformVector(inputVector, outputVector)
                : worldToLocal.transformVector(inputVector, outputVector);
        }

		private function listItems(clonedRoot	: ISceneNode,
								   nodes		: Dictionary,
								   controllers	: Dictionary) : void
		{
			var numControllers : uint = this.numControllers;
			for (var controllerId : uint = 0; controllerId < numControllers; ++controllerId)
				controllers[getController(controllerId)] = true;

			nodes[this] = clonedRoot;

			if (this is Group)
			{
				var group		: Group = Group(this);
				var clonedGroup	: Group = Group(clonedRoot);
				var numChildren	: uint	= group.numChildren;

				for (var childId : uint = 0; childId < numChildren; ++childId)
				{
					var child		: AbstractSceneNode = AbstractSceneNode(group.getChildAt(childId));
					var clonedChild	: AbstractSceneNode = AbstractSceneNode(clonedGroup.getChildAt(childId));

					child.listItems(clonedChild, nodes, controllers);
				}
			}
		}

		private function cloneControllers(controllerMap : Dictionary, cloneOptions : CloneOptions) : void
		{
			for (var objController : Object in controllerMap)
			{
				var controller	: AbstractController = AbstractController(objController);
				var action		: uint				 = cloneOptions.getActionForController(controller);

				if (action == ControllerCloneAction.CLONE)
					controllerMap[controller] = controller.clone();
				else if (action == ControllerCloneAction.REASSIGN)
					controllerMap[controller] = controller;
				else if (action == ControllerCloneAction.IGNORE)
					controllerMap[controller] = null;
				else
					throw new Error();
			}
		}

		private function rebindControllerDependencies(controllerMap	: Dictionary,
													  nodeMap		: Dictionary,
													  cloneOptions	: CloneOptions) : void
		{
			for (var objController : Object in controllerMap)
			{
				var controller	: AbstractController	= AbstractController(objController);
				var action		: uint					= cloneOptions.getActionForController(controller);

				if (controller is IRebindableController && action == ControllerCloneAction.CLONE)
					IRebindableController(controllerMap[controller]).rebindDependencies(nodeMap, controllerMap);
			}
		}
	}
}

package aerys.minko.scene.node
{
	import aerys.minko.ns.minko_scene;
	import aerys.minko.render.shader.part.phong.attenuation.MatrixShadowMapAttenuationShaderPart;
	import aerys.minko.scene.controller.AbstractController;
	import aerys.minko.scene.controller.IRebindableController;
	import aerys.minko.scene.controller.TransformController;
	import aerys.minko.type.Signal;
	import aerys.minko.type.clone.CloneOptions;
	import aerys.minko.type.clone.ControllerCloneAction;
	import aerys.minko.type.math.Matrix4x4;
	import aerys.minko.type.math.Vector4;

	import flash.utils.Dictionary;
	import flash.utils.getQualifiedClassName;
	import flash.utils.setTimeout;

	use namespace minko_scene;

	/**
	 * The base class to extend in order to create new scene node types.
	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public class AbstractSceneNode implements ISceneNode
	{
		private static var _id	    	    	: uint;

		private var _name	    	    		: String;
		private var _root	        			: ISceneNode;
		private var _parent	        			: Group;

		private var _transform			        : Matrix4x4;

		private var _controllers		        : Vector.<AbstractController>;
        private var _transformController        : TransformController;

		private var _added				        : Signal;
		private var _removed			        : Signal;
		private var _controllerAdded	        : Signal;
		private var _controllerRemoved	        : Signal;
        private var _visibilityChanged          : Signal;
        private var _computedVisibilityChanged  : Signal;
		private var _localToWorldChanged		: Signal;

        final public function get x() : Number
		{
			return _transform.translationX;
		}
        final public function set x(value : Number) : void
		{
			_transform.translationX = value;
		}

        final public function get y() : Number
		{
			return _transform.translationX;
		}
        final public function set y(value : Number) : void
		{
			_transform.translationY = value;
		}

        final public function get z() : Number
		{
			return _transform.translationX;
		}
        final public function set z(value : Number) : void
		{
			_transform.translationZ = value;
		}

        final public function get rotationX() : Number
		{
			return _transform.rotationX;
		}
        final public function set rotationX(value : Number) : void
		{
			_transform.rotationX = value;
		}

        final public function get rotationY() : Number
		{
			return _transform.rotationY;
		}
        final public function set rotationY(value : Number) : void
		{
			_transform.rotationY = value;
		}

        final public function get rotationZ() : Number
		{
			return _transform.rotationZ;
		}
        final public function set rotationZ(value : Number) : void
		{
			_transform.rotationZ = value;
		}

        final public function get scaleX() : Number
		{
			return _transform.scaleX;
		}
        final public function set scaleX(value : Number) : void
		{
			_transform.scaleX = value;
		}

        final public function get scaleY() : Number
		{
			return _transform.scaleY;
		}
        final public function set scaleY(value : Number) : void
		{
			_transform.scaleY = value;
		}

        final public function get scaleZ() : Number
		{
			return _transform.scaleZ;
		}
        final public function set scaleZ(value : Number) : void
		{
			_transform.scaleZ = value;
		}

        public function get name() : String
		{
			return _name;
		}
        public function set name(value : String) : void
		{
			_name = value;
		}

        final public function get parent() : Group
		{
			return _parent;
		}
        final public function set parent(value : Group) : void
		{
			if (value == _parent)
				return ;

			// remove child
			if (_parent)
			{
				var oldParent : Group = _parent;

				oldParent._children.splice(oldParent.getChildIndex(this), 1);

				parent._numChildren--;
				_parent = null;
				_removed.execute(this, oldParent);
				oldParent.descendantRemoved.execute(oldParent, this);
			}

			// set parent
			_parent = value;

			// add child
			if (_parent)
			{
				_parent._children[_parent.numChildren] = this;
				_parent._numChildren++;
				_added.execute(this, _parent);
				_parent.descendantAdded.execute(_parent, this);
			}
		}

        final public function get scene() : Scene
        {
            return _root as Scene;
        }

        final public function get root() : ISceneNode
		{
			return _root;
		}

        final public function get transform() : Matrix4x4
		{
			return _transform;
		}

        final public function get added() : Signal
		{
			return _added;
		}

        final public function get removed() : Signal
		{
			return _removed;
		}

		public function get numControllers() : uint
		{
			return _controllers.length;
		}

		public function get controllerAdded() : Signal
		{
			return _controllerAdded;
		}

		public function get controllerRemoved() : Signal
		{
			return _controllerRemoved;
		}

		public function get localToWorldTransformChanged() : Signal
		{
			return _localToWorldChanged;
		}

		public function AbstractSceneNode()
		{
			initialize();
		}

		protected function initialize() : void
		{
			_name = getDefaultSceneName(this);
			_transform = new Matrix4x4();
			_controllers = new <AbstractController>[];
			_root = this;

			initializeSignals();
			initializeSignalHandlers();
			initializeContollers();
			initializeDataProviders();
		}

		protected function initializeSignals() : void
		{
			_added = new Signal('AbstractSceneNode.added');
			_removed = new Signal('AbstractSceneNode.removed');
			_controllerAdded = new Signal('AbstractSceneNode.controllerAdded');
			_controllerRemoved = new Signal('AbstractSceneNode.controllerRemoved');
			_visibilityChanged = new Signal('AbstractSceneNode.visibilityChanged');
			_computedVisibilityChanged = new Signal('AbstractSceneNode.computedVisibilityChanged');
			_localToWorldChanged = new Signal('AbstractSceneNode.localToWorldChanged');
		}

		protected function initializeSignalHandlers() : void
		{
			_added.add(addedHandler);
			_removed.add(removedHandler);
		}

		protected function initializeContollers() : void
		{
            _transformController = new TransformController();
			addController(_transformController);
		}

		protected function initializeDataProviders() : void
		{
			// nothing
		}

		private function addedHandler(child : ISceneNode, ancestor : Group) : void
		{
           _root = _parent ? _parent.root : this;
		}

		private function removedHandler(child : ISceneNode, ancestor : Group) : void
		{
			_root = _parent ? _parent.root : this;
		}

		public function addController(controller : AbstractController) : ISceneNode
		{
			_controllers.push(controller);

			controller.addTarget(this);
			_controllerAdded.execute(this, controller);

			return this;
		}

		public function removeController(controller : AbstractController) : ISceneNode
		{
			var numControllers	: uint  = _controllers.length - 1;
            var controllerId    : int   = _controllers.indexOf(controller);

            if (controllerId < 0)
                throw new Error('The controller is not on the node.');

			_controllers[controllerId] = _controllers[numControllers];
			_controllers.length = numControllers;

			controller.removeTarget(this);
			_controllerRemoved.execute(this, controller);

			return this;
		}

		public function getController(index : uint) : AbstractController
		{
			return _controllers[index];
		}

		public function getControllersByType(type			: Class,
											 controllers	: Vector.<AbstractController> = null) : Vector.<AbstractController>
		{
			controllers ||= new Vector.<AbstractController>();

			var nbControllers : uint = numControllers;

			for (var i : int = 0; i < nbControllers; ++i)
			{
				var ctrl 	: AbstractController	= getController(i);

				if (ctrl is type)
					controllers.push(ctrl);
			}

			return controllers;
		}

		public static function getDefaultSceneName(scene : ISceneNode) : String
		{
			var className : String = getQualifiedClassName(scene);

			return className.substr(className.lastIndexOf(':') + 1)
				   + '_' + (++_id);
		}

		minko_scene function cloneNode() : AbstractSceneNode
		{
			throw new Error('Must be overriden');
		}

		public final function clone(cloneOptions : CloneOptions = null) : ISceneNode
		{
			cloneOptions ||= CloneOptions.defaultOptions;

			// fill up 2 dics with all nodes and controllers
			var nodeMap			: Dictionary = new Dictionary();
			var controllerMap	: Dictionary = new Dictionary();
			listItems(cloneNode(), nodeMap, controllerMap);

			// clone controllers with respect with instructions
			cloneControllers(controllerMap, cloneOptions);

			// rebind all controller dependencies.
			rebindControllerDependencies(controllerMap, nodeMap, cloneOptions);

			// add cloned/rebinded/original controllers to clones
			for (var objNode : Object in nodeMap)
			{
				var node			: AbstractSceneNode = AbstractSceneNode(objNode);
				var numControllers	: uint = node.numControllers;

				for (var controllerId : uint = 0; controllerId < numControllers; ++controllerId)
				{
					var controller : AbstractController = controllerMap[node.getController(controllerId)];
					if (controller != null)
						nodeMap[node].addController(controller);
				}
			}

			return nodeMap[this];
		}

		minko_scene function getLocalToWorldTransformUnsafe(forceUpdate : Boolean = false) : Matrix4x4
		{
            var transformController : TransformController = _root
                ? (_root is AbstractSceneNode
                    ? (_root as AbstractSceneNode)._transformController
                    : _root.getControllersByType(TransformController)[0] as TransformController)
                : _transformController;

            return transformController.getLocalToWorldTransform(this, forceUpdate);
		}

        minko_scene function getWorldToLocalTransformUnsafe(forceUpdate : Boolean = false) : Matrix4x4
        {
            var transformController : TransformController = _root
                ? (_root is AbstractSceneNode
                    ? (_root as AbstractSceneNode)._transformController
                    : _root.getControllersByType(TransformController)[0] as TransformController)
                : _transformController;

            return transformController.getWorldToLocalTransform(this, forceUpdate);
        }

		public function getLocalToWorldTransform(forceUpdate 	: Boolean 	= false,
												 output 		: Matrix4x4 = null) : Matrix4x4
		{
            var transformController : TransformController = _root
                ? (_root is AbstractSceneNode
                    ? (_root as AbstractSceneNode)._transformController
                    : _root.getControllersByType(TransformController)[0] as TransformController)
                : _transformController;

			output ||= new Matrix4x4();
			output.copyFrom(transformController.getLocalToWorldTransform(this, forceUpdate));

			return output;
		}

		public function getWorldToLocalTransform(forceUpdate 	: Boolean 	= false,
												 output			: Matrix4x4 = null) : Matrix4x4
		{
            var transformController : TransformController = _root
                ? (_root is AbstractSceneNode
                    ? (_root as AbstractSceneNode)._transformController
                    : _root.getControllersByType(TransformController)[0] as TransformController)
                : _transformController;

            output ||= new Matrix4x4();
            output.copyFrom(transformController.getWorldToLocalTransform(this, forceUpdate));

			return output;
		}

		public function localToWorld(inputVector 						: Vector4,
									 outputVector 						: Vector4 	= null,
                                     skipTranslation                    : Boolean   = false,
									 forceLocalToWorldTransformUpdate	: Boolean	= false) : Vector4
		{
			var localToWorld : Matrix4x4 = getLocalToWorldTransformUnsafe(
				forceLocalToWorldTransformUpdate
			);

			return skipTranslation
                ? localToWorld.deltaTransformVector(inputVector, outputVector)
                : localToWorld.transformVector(inputVector, outputVector);
		}

        public function worldToLocal(inputVector						: Vector4,
                                     outputVector						: Vector4 	= null,
                                     skipTranslation                    : Boolean   = false,
                                     forceWorldToLocalTransformUpdate	: Boolean	= false) : Vector4
        {
            var worldToLocal : Matrix4x4 = getWorldToLocalTransformUnsafe(
                forceWorldToLocalTransformUpdate
            );

            return skipTranslation
                ? worldToLocal.deltaTransformVector(inputVector, outputVector)
                : worldToLocal.transformVector(inputVector, outputVector);
        }

		private function listItems(clonedRoot	: ISceneNode,
								   nodes		: Dictionary,
								   controllers	: Dictionary) : void
		{
			var numControllers : uint = this.numControllers;
			for (var controllerId : uint = 0; controllerId < numControllers; ++controllerId)
				controllers[getController(controllerId)] = true;

			nodes[this] = clonedRoot;

			if (this is Group)
			{
				var group		: Group = Group(this);
				var clonedGroup	: Group = Group(clonedRoot);
				var numChildren	: uint	= group.numChildren;

				for (var childId : uint = 0; childId < numChildren; ++childId)
				{
					var child		: AbstractSceneNode = AbstractSceneNode(group.getChildAt(childId));
					var clonedChild	: AbstractSceneNode = AbstractSceneNode(clonedGroup.getChildAt(childId));

					child.listItems(clonedChild, nodes, controllers);
				}
			}
		}

		private function cloneControllers(controllerMap : Dictionary, cloneOptions : CloneOptions) : void
		{
			for (var objController : Object in controllerMap)
			{
				var controller	: AbstractController = AbstractController(objController);
				var action		: uint				 = cloneOptions.getActionForController(controller);

				if (action == ControllerCloneAction.CLONE)
					controllerMap[controller] = controller.clone();
				else if (action == ControllerCloneAction.REASSIGN)
					controllerMap[controller] = controller;
				else if (action == ControllerCloneAction.IGNORE)
					controllerMap[controller] = null;
				else
					throw new Error();
			}
		}

		private function rebindControllerDependencies(controllerMap	: Dictionary,
													  nodeMap		: Dictionary,
													  cloneOptions	: CloneOptions) : void
		{
			for (var objController : Object in controllerMap)
			{
				var controller	: AbstractController	= AbstractController(objController);
				var action		: uint					= cloneOptions.getActionForController(controller);

				if (controller is IRebindableController && action == ControllerCloneAction.CLONE)
					IRebindableController(controllerMap[controller]).rebindDependencies(nodeMap, controllerMap);
			}
		}
	}
}

fix AbstractSceneNode transforms get* methods to get the TransformController as fast as possible


package aerys.minko.render
{
	import aerys.minko.ns.minko_render;
	import aerys.minko.render.geometry.Geometry;
	import aerys.minko.render.geometry.stream.IVertexStream;
	import aerys.minko.render.geometry.stream.StreamUsage;
	import aerys.minko.render.geometry.stream.VertexStream;
	import aerys.minko.render.geometry.stream.format.VertexComponent;
	import aerys.minko.render.geometry.stream.format.VertexFormat;
	import aerys.minko.render.resource.Context3DResource;
	import aerys.minko.render.resource.IndexBuffer3DResource;
	import aerys.minko.render.resource.Program3DResource;
	import aerys.minko.render.resource.VertexBuffer3DResource;
	import aerys.minko.render.resource.texture.ITextureResource;
	import aerys.minko.render.shader.binding.IBinder;
	import aerys.minko.type.binding.DataBindings;
	import aerys.minko.type.enum.Blending;
	import aerys.minko.type.enum.ColorMask;
	import aerys.minko.type.enum.TriangleCulling;
	import aerys.minko.type.math.Matrix4x4;
	import aerys.minko.type.math.Vector4;

	import flash.display3D.Context3DProgramType;
	import flash.utils.Dictionary;

	/**
	 * DrawCall objects contain all the shader constants and buffer settings required
	 * to perform drawing operations using the Stage3D API.
	 * @author Jean-Marc Le Roux
	 *
	 */
	public final class DrawCall
	{
		use namespace minko_render;

		private static const PROGRAM_TYPE_VERTEX	: String			= Context3DProgramType.VERTEX;
		private static const PROGRAM_TYPE_FRAGMENT	: String			= Context3DProgramType.FRAGMENT;
		private static const NUM_TEXTURES			: uint				= 8;
		private static const NUM_VERTEX_BUFFERS		: uint				= 8;

		private static const TMP_VECTOR4			: Vector4			= new Vector4();
		private static const TMP_NUMBERS			: Vector.<Number>	= new Vector.<Number>(0xffff, true);
		private static const TMP_INTS				: Vector.<int>		= new Vector.<int>(0xffff, true);

		private var _bindings			: Object							= null;

		private var _vsInputComponents	: Vector.<VertexComponent>			= null;
		private var _vsInputIndices		: Vector.<uint>						= null;
		private var _cpuConstants		: Dictionary						= null;
		private var _vsConstants		: Vector.<Number>					= null;
		private var _fsConstants		: Vector.<Number>					= null;
		private var _fsTextures			: Vector.<ITextureResource>			= new Vector.<ITextureResource>(NUM_TEXTURES, true);

		// states
		private var _indexBuffer		: IndexBuffer3DResource				= null;
		private var _firstIndex			: int								= 0;
		private var _numTriangles		: int								= -1;

		private var _vertexBuffers		: Vector.<VertexBuffer3DResource>	= new Vector.<VertexBuffer3DResource>(NUM_VERTEX_BUFFERS, true);
		private var _numVertexComponents: uint								= 0;
		private var _offsets			: Vector.<int>						= new Vector.<int>(8, true);
		private var _formats			: Vector.<String>					= new Vector.<String>(8, true);

		private var _blending			: uint								= 0;
		private var _blendingSource		: String							= null;
		private var _blendingDest		: String							= null;

		private var _triangleCulling	: uint								= 0;
		private var _triangleCullingStr	: String							= null;

		private var _colorMask			: uint								= 0;
		private var _colorMaskR			: Boolean							= true;
		private var _colorMaskG			: Boolean							= true;
		private var _colorMaskB			: Boolean							= true;
		private var _colorMaskA			: Boolean							= true;

		private var _enabled			: Boolean							= true;

		private var _depth				: Number							= 0.;
        private var _center				: Vector4							= null;
		private var _invalidDepth		: Boolean							= false;
		private var _localToWorld		: Matrix4x4							= null;
		private var _worldToScreen		: Matrix4x4							= null;

        private var _changes            : Object                           = {};

		public function get vertexComponents() : Vector.<VertexComponent>
		{
			return _vsInputComponents;
		}

		public function get blending() : uint
		{
			return _blending;
		}
		public function set blending(value : uint) : void
		{
			_blending = value;
			_blendingSource = Blending.STRINGS[int(value & 0xffff)];
			_blendingDest	= Blending.STRINGS[int(value >>> 16)]
		}

		public function get triangleCulling() : uint
		{
			return _triangleCulling;
		}
		public function set triangleCulling(value : uint) : void
		{
			_triangleCulling = value;
			_triangleCullingStr = TriangleCulling.STRINGS[value];
		}

		public function get colorMask() : uint
		{
			return _colorMask;
		}
		public function set colorMask(value : uint) : void
		{
			_colorMask = value;
			_colorMaskR = (value & ColorMask.RED) != 0;
			_colorMaskG = (value & ColorMask.GREEN) != 0;
			_colorMaskB = (value & ColorMask.BLUE) != 0;
			_colorMaskA = (value & ColorMask.ALPHA) != 0;
		}

		public function get enabled() : Boolean
		{
			return _enabled;
		}
		public function set enabled(value : Boolean) : void
		{
			_enabled = value;

            if (value)
                for (var bindingName : String in _changes)
                {
                    setParameter(bindingName, _changes[bindingName]);
                    delete _changes[bindingName];
                }
		}

		public function get depth() : Number
		{
			if (_invalidDepth && _enabled)
			{
				_invalidDepth = false;

				if (_localToWorld != null && _worldToScreen != null)
				{
					var worldSpacePosition 	: Vector4	= _localToWorld.transformVector(
						_center, TMP_VECTOR4
					);
					var screenSpacePosition : Vector4 	= _worldToScreen.transformVector(
						worldSpacePosition, TMP_VECTOR4
					);

					_depth = screenSpacePosition.z / screenSpacePosition.w;
				}
			}

			return _depth;
		}

		public function configure(program		: Program3DResource,
								  geometry		: Geometry,
								  meshBindings	: DataBindings,
								  sceneBindings	: DataBindings,
								  computeDepth	: Boolean) : void
		{
//			if (_bindings != null)
//				unsetBindings(meshBindings, sceneBindings);

			_invalidDepth = computeDepth;

			setProgram(program);
			setGeometry(geometry);
			setBindings(meshBindings, sceneBindings, computeDepth);
		}

		public function unsetBindings(meshBindings	: DataBindings,
									  sceneBindings	: DataBindings) : void
		{
            _changes = {};

			for (var parameter : String in _bindings)
			{
                if (meshBindings.hasCallback(parameter, parameterChangedHandler))
				    meshBindings.removeCallback(parameter, parameterChangedHandler);
                else if (sceneBindings.hasCallback(parameter, parameterChangedHandler))
    				sceneBindings.removeCallback(parameter, parameterChangedHandler);
			}

			if (sceneBindings.hasCallback('worldToScreen', transformChangedHandler))
				sceneBindings.removeCallback('worldToScreen', transformChangedHandler);

			if (meshBindings.hasCallback('localToWorld', transformChangedHandler))
				meshBindings.removeCallback('localToWorld', transformChangedHandler);
		}

		private function setProgram(program : Program3DResource) : void
		{
			_cpuConstants		= new Dictionary();
			_vsConstants		= program._vsConstants.slice();
			_fsConstants		= program._fsConstants.slice();
			_fsTextures			= program._fsTextures.slice();
			_vsInputComponents	= program._vertexInputComponents;
			_vsInputIndices		= program._vertexInputIndices;
			_bindings			= program._bindings;

			triangleCulling		= TriangleCulling.FRONT;
			blending			= Blending.NORMAL;
			colorMask			= ColorMask.RGBA;
		}

		 /**
		  * Ask geometry to compute additional vertex data if needed for this drawcall.
		  */
		public function updateGeometry(geometry : Geometry) : void
		{
			var vertexFormat : VertexFormat	= geometry.format;

			if (_vsInputComponents.indexOf(VertexComponent.TANGENT) >= 0
				&& !vertexFormat.hasComponent(VertexComponent.TANGENT))
			{
				geometry.computeTangentSpace();
			}
			else if (_vsInputComponents.indexOf(VertexComponent.NORMAL) >= 0
                && !vertexFormat.hasComponent(VertexComponent.NORMAL))
			{
				geometry.computeNormals();
			}
		}

		/**
		 * Obtain a reference to each buffer and offset that apply() may possibly need.
		 *
		 */
		public function setGeometry(geometry : Geometry, frame : uint = 0) : void
		{
			updateGeometry(geometry);

			_center = geometry.boundingSphere
				? geometry.boundingSphere.center
				: Vector4.ZERO;

			_numVertexComponents = _vsInputComponents.length;
			_indexBuffer		 = geometry.indexStream.resource;
			_firstIndex			 = geometry.firstIndex;
			_numTriangles		 = geometry.numTriangles;

			for (var i : uint = 0; i < _numVertexComponents; ++i)
			{
				var component : VertexComponent	= _vsInputComponents[i];
				var index	  : uint			= _vsInputIndices[i];

				if (component)
				{
					var vertexStream	: IVertexStream = geometry.getVertexStream(index + frame);
					var stream	 		: VertexStream	= vertexStream.getStreamByComponent(component);

					if (stream == null)
					{
						throw new Error(
							'Missing vertex component: \'' + component.toString() + '\'.'
						);
					}

					_vertexBuffers[i]	= stream.resource;
					_formats[i]			= component.nativeFormatString;
					_offsets[i]			= stream.format.getOffsetForComponent(component);
				}
			}
		}

		/**
		 * @fixme There is a bug here
		 * @fixme We splitted properties between scene and mesh
		 * @fixme it should be done on the compiler also to avoid this ugly hack
		 */
		private function setBindings(meshBindings	: DataBindings,
									 sceneBindings	: DataBindings,
									 computeDepth	: Boolean) : void
		{
			for (var parameter : String in _bindings)
			{
				meshBindings.addCallback(parameter, parameterChangedHandler);
				sceneBindings.addCallback(parameter, parameterChangedHandler);

				if (meshBindings.propertyExists(parameter))
					setParameter(parameter, meshBindings.getProperty(parameter));
				else if (sceneBindings.propertyExists(parameter))
					setParameter(parameter, sceneBindings.getProperty(parameter));
			}

			if (computeDepth)
			{
				_worldToScreen = sceneBindings.getProperty('worldToScreen') as Matrix4x4;
				_localToWorld = meshBindings.getProperty('localToWorld') as Matrix4x4;

				sceneBindings.addCallback('worldToScreen', transformChangedHandler);
				meshBindings.addCallback('localToWorld', transformChangedHandler);

				_invalidDepth = true;
			}
		}

		public function apply(context : Context3DResource, previous : DrawCall) : uint
		{
			if (!_enabled)
				return 0;

			context.setColorMask(_colorMaskR, _colorMaskG, _colorMaskB, _colorMaskA)
				   .setProgramConstantsFromVector(PROGRAM_TYPE_VERTEX, 0, _vsConstants)
				   .setProgramConstantsFromVector(PROGRAM_TYPE_FRAGMENT, 0, _fsConstants);

			var numTextures	: uint	= _fsTextures.length;
			var maxTextures	: uint	= previous ? previous._fsTextures.length : NUM_TEXTURES;
			var maxBuffers	: uint	= previous ? previous._numVertexComponents : NUM_VERTEX_BUFFERS;
			var i 			: uint 	= 0;

			// setup textures
			for (i = 0; i < numTextures; ++i)
			{
				context.setTextureAt(
					i,
					(_fsTextures[i] as ITextureResource).getTexture(context)
				);
			}

			while (i < maxTextures)
				context.setTextureAt(i++, null);

			// setup buffers
			for (i = 0; i < _numVertexComponents; ++i)
			{
				context.setVertexBufferAt(
					i,
					(_vertexBuffers[i] as VertexBuffer3DResource).getVertexBuffer3D(context),
					_offsets[i],
					_formats[i]
				);
			}

			while (i < maxBuffers)
				context.setVertexBufferAt(i++, null);

			// draw triangles
			context.drawTriangles(
				_indexBuffer.getIndexBuffer3D(context),
				_firstIndex,
				_numTriangles
			);

			return _numTriangles == -1 ? _indexBuffer.numIndices / 3 : _numTriangles;
		}

		public function setParameter(name : String, value : Object) : void
		{
			if (!_enabled)
            {
                _changes[name] = value;

				return ;
            }

			var binding : IBinder = _bindings[name] as IBinder;

			if (binding != null)
				binding.set(_cpuConstants, _vsConstants, _fsConstants, _fsTextures, value);
		}

		private function parameterChangedHandler(dataBindings	: DataBindings,
												 property		: String,
												 oldValue		: Object,
												 newValue		: Object) : void
		{
			newValue !== null && setParameter(property, newValue);
		}

		private function transformChangedHandler(bindings 	: DataBindings,
												 property 	: String,
												 oldValue	: Matrix4x4,
												 newValue 	: Matrix4x4) : void
		{
			if (property == 'worldToScreen')
				_worldToScreen = newValue;
			else if (property == 'localToWorld')
				_localToWorld = newValue;

			_invalidDepth = true;
		}
	}
}

package aerys.minko.render
{
	import aerys.minko.ns.minko_render;
	import aerys.minko.render.geometry.Geometry;
	import aerys.minko.render.geometry.stream.IVertexStream;
	import aerys.minko.render.geometry.stream.StreamUsage;
	import aerys.minko.render.geometry.stream.VertexStream;
	import aerys.minko.render.geometry.stream.format.VertexComponent;
	import aerys.minko.render.geometry.stream.format.VertexFormat;
	import aerys.minko.render.resource.Context3DResource;
	import aerys.minko.render.resource.IndexBuffer3DResource;
	import aerys.minko.render.resource.Program3DResource;
	import aerys.minko.render.resource.VertexBuffer3DResource;
	import aerys.minko.render.resource.texture.ITextureResource;
	import aerys.minko.render.shader.binding.IBinder;
	import aerys.minko.type.binding.DataBindings;
	import aerys.minko.type.enum.Blending;
	import aerys.minko.type.enum.ColorMask;
	import aerys.minko.type.enum.TriangleCulling;
	import aerys.minko.type.math.Matrix4x4;
	import aerys.minko.type.math.Vector4;

	import flash.display3D.Context3DProgramType;
	import flash.utils.Dictionary;

	/**
	 * DrawCall objects contain all the shader constants and buffer settings required
	 * to perform drawing operations using the Stage3D API.
	 * @author Jean-Marc Le Roux
	 *
	 */
	public final class DrawCall
	{
		use namespace minko_render;

		private static const PROGRAM_TYPE_VERTEX	: String			= Context3DProgramType.VERTEX;
		private static const PROGRAM_TYPE_FRAGMENT	: String			= Context3DProgramType.FRAGMENT;
		private static const NUM_TEXTURES			: uint				= 8;
		private static const NUM_VERTEX_BUFFERS		: uint				= 8;

		private static const TMP_VECTOR4			: Vector4			= new Vector4();
		private static const TMP_NUMBERS			: Vector.<Number>	= new Vector.<Number>(0xffff, true);
		private static const TMP_INTS				: Vector.<int>		= new Vector.<int>(0xffff, true);

		private var _bindings			: Object							= null;

		private var _vsInputComponents	: Vector.<VertexComponent>			= null;
		private var _vsInputIndices		: Vector.<uint>						= null;
		private var _cpuConstants		: Dictionary						= null;
		private var _vsConstants		: Vector.<Number>					= null;
		private var _fsConstants		: Vector.<Number>					= null;
		private var _fsTextures			: Vector.<ITextureResource>			= new Vector.<ITextureResource>(NUM_TEXTURES, true);

		// states
		private var _indexBuffer		: IndexBuffer3DResource				= null;
		private var _firstIndex			: int								= 0;
		private var _numTriangles		: int								= -1;

		private var _vertexBuffers		: Vector.<VertexBuffer3DResource>	= new Vector.<VertexBuffer3DResource>(NUM_VERTEX_BUFFERS, true);
		private var _numVertexComponents: uint								= 0;
		private var _offsets			: Vector.<int>						= new Vector.<int>(8, true);
		private var _formats			: Vector.<String>					= new Vector.<String>(8, true);

		private var _blending			: uint								= 0;
		private var _blendingSource		: String							= null;
		private var _blendingDest		: String							= null;

		private var _triangleCulling	: uint								= 0;
		private var _triangleCullingStr	: String							= null;

		private var _colorMask			: uint								= 0;
		private var _colorMaskR			: Boolean							= true;
		private var _colorMaskG			: Boolean							= true;
		private var _colorMaskB			: Boolean							= true;
		private var _colorMaskA			: Boolean							= true;

		private var _enabled			: Boolean							= true;

		private var _depth				: Number							= 0.;
        private var _center				: Vector4							= null;
		private var _invalidDepth		: Boolean							= false;
		private var _localToWorld		: Matrix4x4							= null;
		private var _worldToScreen		: Matrix4x4							= null;

        private var _changes            : Object                           = {};

		public function get vertexComponents() : Vector.<VertexComponent>
		{
			return _vsInputComponents;
		}

		public function get blending() : uint
		{
			return _blending;
		}
		public function set blending(value : uint) : void
		{
			_blending = value;
			_blendingSource = Blending.STRINGS[int(value & 0xffff)];
			_blendingDest	= Blending.STRINGS[int(value >>> 16)]
		}

		public function get triangleCulling() : uint
		{
			return _triangleCulling;
		}
		public function set triangleCulling(value : uint) : void
		{
			_triangleCulling = value;
			_triangleCullingStr = TriangleCulling.STRINGS[value];
		}

		public function get colorMask() : uint
		{
			return _colorMask;
		}
		public function set colorMask(value : uint) : void
		{
			_colorMask = value;
			_colorMaskR = (value & ColorMask.RED) != 0;
			_colorMaskG = (value & ColorMask.GREEN) != 0;
			_colorMaskB = (value & ColorMask.BLUE) != 0;
			_colorMaskA = (value & ColorMask.ALPHA) != 0;
		}

		public function get enabled() : Boolean
		{
			return _enabled;
		}
		public function set enabled(value : Boolean) : void
		{
			_enabled = value;

            if (value)
                for (var bindingName : String in _changes)
                {
                    setParameter(bindingName, _changes[bindingName]);
                    delete _changes[bindingName];
                }
		}

		public function get depth() : Number
		{
			if (_invalidDepth && _enabled)
			{
				_invalidDepth = false;

				if (_localToWorld != null && _worldToScreen != null)
				{
					var worldSpacePosition 	: Vector4	= _localToWorld.transformVector(
						_center, TMP_VECTOR4
					);
					var screenSpacePosition : Vector4 	= _worldToScreen.transformVector(
						worldSpacePosition, TMP_VECTOR4
					);

					_depth = screenSpacePosition.z / screenSpacePosition.w;
				}
			}

			return _depth;
		}

		public function configure(program		: Program3DResource,
								  geometry		: Geometry,
								  meshBindings	: DataBindings,
								  sceneBindings	: DataBindings,
								  computeDepth	: Boolean) : void
		{
//			if (_bindings != null)
//				unsetBindings(meshBindings, sceneBindings);

			_invalidDepth = computeDepth;

			setProgram(program);
			setGeometry(geometry);
			setBindings(meshBindings, sceneBindings, computeDepth);
		}

		public function unsetBindings(meshBindings	: DataBindings,
									  sceneBindings	: DataBindings) : void
		{
            _changes = {};

			for (var parameter : String in _bindings)
			{
                if (meshBindings.hasCallback(parameter, parameterChangedHandler))
				    meshBindings.removeCallback(parameter, parameterChangedHandler);
                else if (sceneBindings.hasCallback(parameter, parameterChangedHandler))
    				sceneBindings.removeCallback(parameter, parameterChangedHandler);
			}

			if (sceneBindings.hasCallback('worldToScreen', transformChangedHandler))
				sceneBindings.removeCallback('worldToScreen', transformChangedHandler);

			if (meshBindings.hasCallback('localToWorld', transformChangedHandler))
				meshBindings.removeCallback('localToWorld', transformChangedHandler);
		}

		private function setProgram(program : Program3DResource) : void
		{
			_cpuConstants		= new Dictionary();
			_vsConstants		= program._vsConstants.slice();
			_fsConstants		= program._fsConstants.slice();
			_fsTextures			= program._fsTextures.slice();
			_vsInputComponents	= program._vertexInputComponents;
			_vsInputIndices		= program._vertexInputIndices;
			_bindings			= program._bindings;

			triangleCulling		= TriangleCulling.FRONT;
			blending			= Blending.NORMAL;
			colorMask			= ColorMask.RGBA;
		}

		 /**
		  * Ask geometry to compute additional vertex data if needed for this drawcall.
		  */
		public function updateGeometry(geometry : Geometry) : void
		{
			var vertexFormat : VertexFormat	= geometry.format;

			if (_vsInputComponents.indexOf(VertexComponent.TANGENT) >= 0
				&& !vertexFormat.hasComponent(VertexComponent.TANGENT))
			{
				geometry.computeTangentSpace();
			}
			else if (_vsInputComponents.indexOf(VertexComponent.NORMAL) >= 0
                && !vertexFormat.hasComponent(VertexComponent.NORMAL))
			{
				geometry.computeNormals();
			}
		}

		/**
		 * Obtain a reference to each buffer and offset that apply() may possibly need.
		 *
		 */
		public function setGeometry(geometry : Geometry, frame : uint = 0) : void
		{
			updateGeometry(geometry);

			_center = geometry.boundingSphere
				? geometry.boundingSphere.center
				: Vector4.ZERO;

			_numVertexComponents = _vsInputComponents.length;
			_indexBuffer		 = geometry.indexStream.resource;
			_firstIndex			 = geometry.firstIndex;
			_numTriangles		 = geometry.numTriangles;

			for (var i : uint = 0; i < _numVertexComponents; ++i)
			{
				var component : VertexComponent	= _vsInputComponents[i];
				var index	  : uint			= _vsInputIndices[i];

				if (component)
				{
					var vertexStream	: IVertexStream = geometry.getVertexStream(index + frame);
					var stream	 		: VertexStream	= vertexStream.getStreamByComponent(component);

					if (stream == null)
					{
						throw new Error(
							'Missing vertex component: \'' + component.toString() + '\'.'
						);
					}

					_vertexBuffers[i]	= stream.resource;
					_formats[i]			= component.nativeFormatString;
					_offsets[i]			= stream.format.getOffsetForComponent(component);
				}
			}
		}

		/**
		 * @fixme There is a bug here
		 * @fixme We splitted properties between scene and mesh
		 * @fixme it should be done on the compiler also to avoid this ugly hack
		 */
		private function setBindings(meshBindings	: DataBindings,
									 sceneBindings	: DataBindings,
									 computeDepth	: Boolean) : void
		{
			for (var parameter : String in _bindings)
			{
				meshBindings.addCallback(parameter, parameterChangedHandler);
                if (!sceneBindings.hasCallback(parameter, parameterChangedHandler))
    				sceneBindings.addCallback(parameter, parameterChangedHandler);

				if (meshBindings.propertyExists(parameter))
					setParameter(parameter, meshBindings.getProperty(parameter));
				else if (sceneBindings.propertyExists(parameter))
					setParameter(parameter, sceneBindings.getProperty(parameter));
			}

			if (computeDepth)
			{
				_worldToScreen = sceneBindings.getProperty('worldToScreen') as Matrix4x4;
				_localToWorld = meshBindings.getProperty('localToWorld') as Matrix4x4;

				sceneBindings.addCallback('worldToScreen', transformChangedHandler);
				meshBindings.addCallback('localToWorld', transformChangedHandler);

				_invalidDepth = true;
			}
		}

		public function apply(context : Context3DResource, previous : DrawCall) : uint
		{
			if (!_enabled)
				return 0;

			context.setColorMask(_colorMaskR, _colorMaskG, _colorMaskB, _colorMaskA)
				   .setProgramConstantsFromVector(PROGRAM_TYPE_VERTEX, 0, _vsConstants)
				   .setProgramConstantsFromVector(PROGRAM_TYPE_FRAGMENT, 0, _fsConstants);

			var numTextures	: uint	= _fsTextures.length;
			var maxTextures	: uint	= previous ? previous._fsTextures.length : NUM_TEXTURES;
			var maxBuffers	: uint	= previous ? previous._numVertexComponents : NUM_VERTEX_BUFFERS;
			var i 			: uint 	= 0;

			// setup textures
			for (i = 0; i < numTextures; ++i)
			{
				context.setTextureAt(
					i,
					(_fsTextures[i] as ITextureResource).getTexture(context)
				);
			}

			while (i < maxTextures)
				context.setTextureAt(i++, null);

			// setup buffers
			for (i = 0; i < _numVertexComponents; ++i)
			{
				context.setVertexBufferAt(
					i,
					(_vertexBuffers[i] as VertexBuffer3DResource).getVertexBuffer3D(context),
					_offsets[i],
					_formats[i]
				);
			}

			while (i < maxBuffers)
				context.setVertexBufferAt(i++, null);

			// draw triangles
			context.drawTriangles(
				_indexBuffer.getIndexBuffer3D(context),
				_firstIndex,
				_numTriangles
			);

			return _numTriangles == -1 ? _indexBuffer.numIndices / 3 : _numTriangles;
		}

		public function setParameter(name : String, value : Object) : void
		{
			if (!_enabled)
            {
                _changes[name] = value;

				return ;
            }

			var binding : IBinder = _bindings[name] as IBinder;

			if (binding != null)
				binding.set(_cpuConstants, _vsConstants, _fsConstants, _fsTextures, value);
		}

		private function parameterChangedHandler(dataBindings	: DataBindings,
												 property		: String,
												 oldValue		: Object,
												 newValue		: Object) : void
		{
			newValue !== null && setParameter(property, newValue);
		}

		private function transformChangedHandler(bindings 	: DataBindings,
												 property 	: String,
												 oldValue	: Matrix4x4,
												 newValue 	: Matrix4x4) : void
		{
			if (property == 'worldToScreen')
				_worldToScreen = newValue;
			else if (property == 'localToWorld')
				_localToWorld = newValue;

			_invalidDepth = true;
		}
	}
}

fix DrawCall.setBindings() to avoid listening to the same scene binding twice


package aerys.minko.scene.node
{
	import aerys.minko.ns.minko_scene;
	import aerys.minko.render.geometry.Geometry;
	import aerys.minko.render.material.Material;
	import aerys.minko.render.material.basic.BasicMaterial;
	import aerys.minko.scene.controller.mesh.MeshController;
	import aerys.minko.scene.controller.mesh.MeshVisibilityController;
	import aerys.minko.type.Signal;
	import aerys.minko.type.binding.DataBindings;
	import aerys.minko.type.binding.DataProvider;
	import aerys.minko.type.enum.DataProviderUsage;
	import aerys.minko.type.enum.FrustumCulling;
	import aerys.minko.type.math.Ray;

	use namespace minko_scene;

	/**
	 * Mesh objects are a visible instance of a Geometry rendered using a specific
	 * Effect with specific rendering properties.
	 *
	 *

	 * Those rendering properties are stored in a DataBindings object so they can
	 * be directly used by the shaders in the rendering API.
	 *

	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public class Mesh extends AbstractVisibleSceneNode implements ITaggable
	{
		public static const DEFAULT_MATERIAL	: Material	= new BasicMaterial();

		private var _ctrl				: MeshController;
		private var _properties			: DataProvider;
		private var _material			: Material;
		private var _bindings			: DataBindings;

		private var _visibility			: MeshVisibilityController;

		private var _cloned				: Signal;

		private var _tag				: uint = 1;

		/**
		 * A DataProvider object already bound to the Mesh bindings.
		 *
		 *

		 * // set the "diffuseColor" property to 0x0000ffff
		 * mesh.properties.diffuseColor = 0x0000ffff;
		 *
		 * // animate the "diffuseColor" property
		 * mesh.addController(
		 *   new AnimationController(
		 * 	  new <ITimeline>[new ColorTimeline(
		 * 	    "dataProvider.diffuseColor",
		 * 	    5000,
		 * 	    new <uint>[0xffffffff, 0xffffff00, 0xffffffff]
		 *    )]
		 *   )
		 * );
		 *

		 *
		 * @return
		 *
		 */
		public function get properties() : DataProvider
		{
			return _properties;
		}

		public function set properties(value : DataProvider) : void
		{
			if (_properties != value)
			{
				if (_properties)
					_bindings.removeProvider(_properties);

				_properties = value;

				if (value)
					_bindings.addProvider(value);
			}
		}

		public function get material() : Material
		{
			return _material;
		}
		public function set material(value : Material) : void
		{
			if (_material != value)
			{
				if (_material)
					_bindings.removeProvider(_material);

				var oldMaterial : Material = _material;

				_material = value;

				if (value)
					_bindings.addProvider(value);
			}
		}

		/**
		 * The rendering properties provided to the shaders to customize
		 * how the mesh will appear on screen.
		 *
		 * @return
		 *
		 */
		public function get bindings() : DataBindings
		{
			return _bindings;
		}

		/**
		 * The Geometry of the mesh.
		 * @return
		 *
		 */
		public function get geometry() : Geometry
		{
			return _ctrl.geometry;
		}

		public function set geometry(value : Geometry) : void
		{
			_ctrl.geometry = value;
		}

		public function get tag() : uint
		{
			return _tag;
		}

		public function set tag(value : uint) : void
		{
			if (_tag != value)
			{
				_tag = value;
				_properties.setProperty('tag', value);
			}
		}

        /**
         * Whether the mesh in inside the camera frustum or not.
         * @return
         *
         */
        public function get insideFrustum() : Boolean
        {
            return _visibility.insideFrustum;
        }

        override public function get computedVisibility() : Boolean
        {
            return scene
				? super.computedVisibility && _visibility.computedVisibility
				: super.computedVisibility;
        }

		public function get frustumCulling() : uint
		{
			return _visibility.frustumCulling;
		}
		public function set frustumCulling(value : uint) : void
		{
			_visibility.frustumCulling = value;
		}

		public function get cloned() : Signal
		{
			return _cloned;
		}

		public function get frame() : uint
		{
			return _ctrl.frame;
		}
		public function set frame(value : uint) : void
		{
			_ctrl.frame = value;
		}

		public function Mesh(geometry	: Geometry	= null,
							 material	: Material	= null,
							 name		: String	= null,
							 tag		: uint		= 1)
		{
			super();

			initializeMesh(geometry, material, name, tag);
		}

		override protected function initialize() : void
		{
			_bindings = new DataBindings(this);
			this.properties = new DataProvider(
				properties,
				'meshProperties',
				DataProviderUsage.EXCLUSIVE
			);

			super.initialize();
		}

		override protected function initializeSignals():void
		{
			super.initializeSignals();

			_cloned = new Signal('Mesh.cloned');
		}

		override protected function initializeContollers():void
		{
			super.initializeContollers();

			_ctrl = new MeshController();
			addController(_ctrl);

			_visibility = new MeshVisibilityController();
			_visibility.frustumCulling = FrustumCulling.ENABLED;
			addController(_visibility);
		}

		protected function initializeMesh(geometry	: Geometry,
										  material	: Material,
										  name		: String,
										  tag		: uint) : void
		{
			if (name)
				this.name = name;

			this.geometry	= geometry;
			this.material	= material || DEFAULT_MATERIAL;
			_tag			= tag;
		}

		public function cast(ray            : Ray,
                             maxDistance    : Number    = Number.POSITIVE_INFINITY,
                             tag            : uint      = 1) : Number
		{
			if (!(_tag & tag))
				return -1;

			return _ctrl.geometry.boundingBox.testRay(
				ray,
				getWorldToLocalTransform(),
				maxDistance
			);
		}

		override minko_scene function cloneNode() : AbstractSceneNode
		{
			var clone : Mesh = new Mesh();

			clone.name 		= name;
			clone.geometry 	= _ctrl.geometry;

			clone.properties = DataProvider(_properties.clone());
			clone._bindings.copySharedProvidersFrom(_bindings);

			clone.transform.copyFrom(transform);
			clone.material = _material;

			this.cloned.execute(this, clone);

			return clone;
		}
	}
}

package aerys.minko.scene.node
{
	import aerys.minko.ns.minko_scene;
	import aerys.minko.render.geometry.Geometry;
	import aerys.minko.render.material.Material;
	import aerys.minko.render.material.basic.BasicMaterial;
	import aerys.minko.scene.controller.mesh.MeshController;
	import aerys.minko.scene.controller.mesh.MeshVisibilityController;
	import aerys.minko.type.Signal;
	import aerys.minko.type.binding.DataBindings;
	import aerys.minko.type.binding.DataProvider;
	import aerys.minko.type.enum.DataProviderUsage;
	import aerys.minko.type.enum.FrustumCulling;
	import aerys.minko.type.math.Ray;

	use namespace minko_scene;

	/**
	 * Mesh objects are a visible instance of a Geometry rendered using a specific
	 * Effect with specific rendering properties.
	 *
	 *

	 * Those rendering properties are stored in a DataBindings object so they can
	 * be directly used by the shaders in the rendering API.
	 *

	 *
	 * @author Jean-Marc Le Roux
	 *
	 */
	public class Mesh extends AbstractVisibleSceneNode implements ITaggable
	{
		public static const DEFAULT_MATERIAL	: Material	= new BasicMaterial();

		private var _ctrl				: MeshController;
		private var _properties			: DataProvider;
		private var _material			: Material;
		private var _bindings			: DataBindings;

		private var _visibility			: MeshVisibilityController;

		private var _cloned				: Signal;

		private var _tag				: uint = 1;

		/**
		 * A DataProvider object already bound to the Mesh bindings.
		 *
		 *

		 * // set the "diffuseColor" property to 0x0000ffff
		 * mesh.properties.diffuseColor = 0x0000ffff;
		 *
		 * // animate the "diffuseColor" property
		 * mesh.addController(
		 *   new AnimationController(
		 * 	  new <ITimeline>[new ColorTimeline(
		 * 	    "dataProvider.diffuseColor",
		 * 	    5000,
		 * 	    new <uint>[0xffffffff, 0xffffff00, 0xffffffff]
		 *    )]
		 *   )
		 * );
		 *

		 *
		 * @return
		 *
		 */
		public function get properties() : DataProvider
		{
			return _properties;
		}

		public function set properties(value : DataProvider) : void
		{
			if (_properties != value)
			{
				if (_properties)
					_bindings.removeProvider(_properties);

				_properties = value;

				if (value)
					_bindings.addProvider(value);
			}
		}

		public function get material() : Material
		{
			return _material;
		}
		public function set material(value : Material) : void
		{
			if (_material != value)
			{
				if (_material)
					_bindings.removeProvider(_material);

				var oldMaterial : Material = _material;

				_material = value;

				if (value)
					_bindings.addProvider(value);
			}
		}

		/**
		 * The rendering properties provided to the shaders to customize
		 * how the mesh will appear on screen.
		 *
		 * @return
		 *
		 */
		public function get bindings() : DataBindings
		{
			return _bindings;
		}

		/**
		 * The Geometry of the mesh.
		 * @return
		 *
		 */
		public function get geometry() : Geometry
		{
			return _ctrl.geometry;
		}

		public function set geometry(value : Geometry) : void
		{
			_ctrl.geometry = value;
		}

		public function get tag() : uint
		{
			return _tag;
		}

		public function set tag(value : uint) : void
		{
			if (_tag != value)
			{
				_tag = value;
				_properties.setProperty('tag', value);
			}
		}

        /**
         * Whether the mesh in inside the camera frustum or not.
         * @return
         *
         */
        public function get insideFrustum() : Boolean
        {
            return _visibility.insideFrustum;
        }

        override public function get computedVisibility() : Boolean
        {
            return scene
				? super.computedVisibility && _visibility.computedVisibility
				: super.computedVisibility;
        }

		public function get frustumCulling() : uint
		{
			return _visibility.frustumCulling;
		}
		public function set frustumCulling(value : uint) : void
		{
			_visibility.frustumCulling = value;
		}

		public function get cloned() : Signal
		{
			return _cloned;
		}

		public function get frame() : uint
		{
			return _ctrl.frame;
		}
		public function set frame(value : uint) : void
		{
			_ctrl.frame = value;
		}

		public function Mesh(geometry	: Geometry	= null,
							 material	: Material	= null,
							 name		: String	= null,
							 tag		: uint		= 1)
		{
			super();

			initializeMesh(geometry, material, name, tag);
		}

		override protected function initialize() : void
		{
			_bindings = new DataBindings(this);
			this.properties = new DataProvider(
				properties,
				'meshProperties',
				DataProviderUsage.EXCLUSIVE
			);

			super.initialize();
		}

		override protected function initializeSignals() : void
		{
			super.initializeSignals();

			_cloned = new Signal('Mesh.cloned');
		}

		override protected function initializeContollers() : void
		{
			super.initializeContollers();

			_ctrl = new MeshController();
			addController(_ctrl);

			_visibility = new MeshVisibilityController();
			_visibility.frustumCulling = FrustumCulling.ENABLED;
			addController(_visibility);
		}

		protected function initializeMesh(geometry	: Geometry,
										  material	: Material,
										  name		: String,
										  tag		: uint) : void
		{
			if (name)
				this.name = name;

			this.geometry	= geometry;
			this.material	= material || DEFAULT_MATERIAL;
			_tag			= tag;
		}

		public function cast(ray            : Ray,
                             maxDistance    : Number    = Number.POSITIVE_INFINITY,
                             tag            : uint      = 1) : Number
		{
			if (!(_tag & tag))
				return -1;

			return _ctrl.geometry.boundingBox.testRay(
				ray,
				getWorldToLocalTransform(),
				maxDistance
			);
		}

		override minko_scene function cloneNode() : AbstractSceneNode
		{
			var clone : Mesh = new Mesh();

			clone.name 		= name;
			clone.geometry 	= _ctrl.geometry;

			clone.properties = DataProvider(_properties.clone());
			clone._bindings.copySharedProvidersFrom(_bindings);

			clone.transform.copyFrom(transform);
			clone.material = _material;

			this.cloned.execute(this, clone);

			return clone;
		}
	}
}

fix coding style

fix coding style


////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2008-2016 Esri. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
////////////////////////////////////////////////////////////////////////////////
package com.esri.builder.controllers.supportClasses
{

import com.esri.builder.model.CustomWidgetType;
import com.esri.builder.model.WidgetType;
import com.esri.builder.supportClasses.FileUtil;
import com.esri.builder.supportClasses.LogUtil;

import flash.events.EventDispatcher;
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
import flash.utils.ByteArray;

import modules.IBuilderModule;
import modules.supportClasses.CustomXMLModule;

import mx.core.FlexGlobals;
import mx.events.ModuleEvent;
import mx.logging.ILogger;
import mx.logging.Log;
import mx.modules.IModuleInfo;
import mx.modules.ModuleManager;

public class WidgetTypeLoader extends EventDispatcher
{
    private static const LOG:ILogger = LogUtil.createLogger(WidgetTypeLoader);

    internal static var loadedModuleInfos:Array = [];

    private var swf:File;
    private var config:File;

    //need reference when loading to avoid being garbage collected before load completes
    private var moduleInfo:IModuleInfo;

    //requires either swf or config
    public function WidgetTypeLoader(swf:File = null, config:File = null)
    {
        this.swf = swf;
        this.config = config;
    }

    public function get name():String
    {
        var fileName:String;

        if (swf && swf.exists)
        {
            fileName = FileUtil.getFileName(swf);
        }
        else if (config && config.exists)
        {
            fileName = FileUtil.getFileName(config);
        }

        return fileName;
    }

    public function load():void
    {
        if (swf && swf.exists)
        {
            loadModule();
        }
        else if (config && config.exists)
        {
            loadConfigModule();
        }
        else
        {
            dispatchError();
        }
    }

    private function loadConfigModule():void
    {
        if (Log.isInfo())
        {
            LOG.info('Loading XML module: {0}', config.url);
        }

        var moduleConfig:XML = readModuleConfig(config);
        if (moduleConfig)
        {
            var customWidgetType:CustomWidgetType = parseCustomWidgetType(moduleConfig);
            if (customWidgetType)
            {
                dispatchComplete(customWidgetType);
                return;
            }
        }

        dispatchError();
    }

    private function loadModule():void
    {
        if (Log.isInfo())
        {
            LOG.info('Loading SWF module: {0}', swf.url);
        }

        moduleInfo = ModuleManager.getModule(swf.url);

        if (moduleInfo.ready)
        {
            if (Log.isInfo())
            {
                LOG.info('Unloading module: {0}', swf.url);
            }

            moduleInfo.addEventListener(ModuleEvent.UNLOAD, moduleInfo_unloadHandler);
            moduleInfo.release();
            moduleInfo.unload();
        }
        else
        {
            if (Log.isInfo())
            {
                LOG.info('Loading module: {0}', swf.url);
            }

            var fileBytes:ByteArray = new ByteArray();
            var fileStream:FileStream = new FileStream();
            fileStream.open(swf, FileMode.READ);
            fileStream.readBytes(fileBytes);
            fileStream.close();

            //Use ModuleEvent.PROGRESS instead of ModuleEvent.READY to avoid the case where the latter is never dispatched.
            moduleInfo.addEventListener(ModuleEvent.PROGRESS, moduleInfo_progressHandler);
            moduleInfo.addEventListener(ModuleEvent.ERROR, moduleInfo_errorHandler);
            moduleInfo.load(null, null, fileBytes, FlexGlobals.topLevelApplication.moduleFactory);
        }
    }

    private function moduleInfo_progressHandler(event:ModuleEvent):void
    {
        if (event.bytesLoaded == event.bytesTotal)
        {
            var moduleInfo:IModuleInfo = event.currentTarget as IModuleInfo;
            moduleInfo.removeEventListener(ModuleEvent.PROGRESS, moduleInfo_progressHandler);
            moduleInfo.removeEventListener(ModuleEvent.ERROR, moduleInfo_errorHandler);
            FlexGlobals.topLevelApplication.callLater(processModuleInfo, [ moduleInfo ]);
        }
    }

    private function moduleInfo_unloadHandler(event:ModuleEvent):void
    {
        if (Log.isInfo())
        {
            LOG.info('Module unloaded: {0}', swf.url);
        }

        var moduleInfo:IModuleInfo = event.module;
        moduleInfo.removeEventListener(ModuleEvent.UNLOAD, moduleInfo_unloadHandler);
        var moduleInfoIndex:int = loadedModuleInfos.indexOf(moduleInfo);
        if (moduleInfoIndex > -1)
        {
            loadedModuleInfos.splice(moduleInfoIndex, 1);
        }
        this.moduleInfo = null;
        FlexGlobals.topLevelApplication.callLater(loadModule);
    }

    private function processModuleInfo(moduleInfo:IModuleInfo):void
    {
        if (Log.isInfo())
        {
            LOG.info('Module loaded: {0}', swf.url);
        }

        if (config && config.exists)
        {
            if (Log.isInfo())
            {
                LOG.info('Reading module config: {0}', config.url);
            }
            var moduleConfig:XML = readModuleConfig(config);
        }

        const builderModule:IBuilderModule = moduleInfo.factory.create() as IBuilderModule;
        if (builderModule)
        {
            if (Log.isInfo())
            {
                LOG.info('Widget type created for module: {0}', swf.url);
            }
            var widgetType:WidgetType = getWidgetType(moduleInfo, builderModule, moduleConfig);
        }

        loadedModuleInfos.push(moduleInfo);
        this.moduleInfo = null;
        dispatchComplete(widgetType);
    }

    private function dispatchComplete(widgetType:WidgetType):void
    {
        if (Log.isInfo())
        {
            LOG.info('Module load complete: {0}', name);
        }

        dispatchEvent(new WidgetTypeLoaderEvent(WidgetTypeLoaderEvent.LOAD_COMPLETE, widgetType));
    }

    private function getWidgetType(moduleInfo:IModuleInfo, builderModule:IBuilderModule, moduleConfig:XML):WidgetType
    {
        var customModulesDirectoryURL:String = WellKnownDirectories.getInstance().customModules.url;
        var isCustomModule:Boolean = (moduleInfo.url.indexOf(customModulesDirectoryURL) > -1);
        if (moduleConfig)
        {
            var configXML:XML = moduleConfig.configuration[0];
            var version:String = moduleConfig.widgetversion[0];
        }

        return isCustomModule ?
            new CustomWidgetType(builderModule, version, configXML) :
            new WidgetType(builderModule);
    }

    private function readModuleConfig(configFile:File):XML
    {
        var configXML:XML;

        var fileStream:FileStream = new FileStream();
        try
        {
            fileStream.open(configFile, FileMode.READ);
            configXML = XML(fileStream.readUTFBytes(fileStream.bytesAvailable));
        }
        catch (e:Error)
        {
            //ignore
            if (Log.isInfo())
            {
                LOG.info('Could not read module config: {0}', e.toString());
            }
        }
        finally
        {
            fileStream.close();
        }

        return configXML;
    }

    private function moduleInfo_errorHandler(event:ModuleEvent):void
    {
        var moduleInfo:IModuleInfo = event.module;
        moduleInfo.removeEventListener(ModuleEvent.ERROR, moduleInfo_errorHandler);
        moduleInfo.removeEventListener(ModuleEvent.PROGRESS, moduleInfo_progressHandler);
        this.moduleInfo = null;
        dispatchError();
    }

    private function dispatchError():void
    {
        if (Log.isInfo())
        {
            LOG.info('Module load failed: {0}', name);
        }

        dispatchEvent(new WidgetTypeLoaderEvent(WidgetTypeLoaderEvent.LOAD_ERROR));
    }

    private function parseCustomWidgetType(configXML:XML):CustomWidgetType
    {
        if (Log.isInfo())
        {
            LOG.info('Creating widget type from XML: {0}', configXML);
        }

        var customModule:CustomXMLModule = new CustomXMLModule();
        customModule.widgetName = configXML.name;
        customModule.isOpenByDefault = (configXML.openbydefault == 'true');

        var widgetLabel:String = configXML.label[0];
        var widgetDescription:String = configXML.description[0];
        var widgetHelpURL:String = configXML.helpurl[0];
        var widgetConfiguration:XML = configXML.configuration[0] ? configXML.configuration[0] : <configuration/>;
        var widgetVersion:String = configXML.widgetversion[0];

        customModule.widgetIconLocation = createWidgetIconPath(configXML.icon[0], customModule.widgetName);
        customModule.widgetLabel = widgetLabel ? widgetLabel : customModule.widgetName;
        customModule.widgetDescription = widgetDescription ? widgetDescription : "";
        customModule.widgetHelpURL = widgetHelpURL ? widgetHelpURL : "";

        return new CustomWidgetType(customModule, widgetVersion, widgetConfiguration);
    }

    private function createWidgetIconPath(iconPath:String, widgetName:String):String
    {
        var widgetIconPath:String;

        if (iconPath)
        {
            widgetIconPath = "widgets/" + widgetName + "/" + iconPath;
        }
        else
        {
            widgetIconPath = "assets/images/i_widget.png";
        }

        return widgetIconPath;
    }
}
}

Remove extra newline.

Remove extra newline.


////////////////////////////////////////////////////////////////////////////////
//
//  Licensed to the Apache Software Foundation (ASF) under one or more
//  contributor license agreements.  See the NOTICE file distributed with
//  this work for additional information regarding copyright ownership.
//  The ASF licenses this file to You under the Apache License, Version 2.0
//  (the "License"); you may not use this file except in compliance with
//  the License.  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package org.apache.flex.events
{
    COMPILE::AS3
    {
        import flash.events.MouseEvent;
    }

    import org.apache.flex.core.IUIBase;
    import org.apache.flex.geom.Point;
    import org.apache.flex.utils.PointUtils;

	/**
	 *  Mouse events
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion FlexJS 0.0
	 */
	public class MouseEvent extends Event
	{
		public static const MOUSE_DOWN:String = "mouseDown";
        public static const MOUSE_MOVE:String = "mouseMove";
		public static const MOUSE_UP:String = "mouseUp";
		public static const MOUSE_OUT:String = "mouseOut";
		public static const MOUSE_OVER:String = "mouseOver";
		public static const ROLL_OVER:String = "rollOver";
		public static const ROLL_OUT:String = "rollOut";
        public static const CLICK:String = "click";

         /**
         *  Constructor.
         *
         *  @param type The name of the event.
         *  @param bubbles Whether the event bubbles.
         *  @param cancelable Whether the event can be canceled.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function MouseEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false,
                                   localX:Number = NaN, localY:Number = NaN,
                                   relatedObject:Object = null,
                                   ctrlKey:Boolean = false, altKey:Boolean = false, shiftKey:Boolean = false,
                                   buttonDown:Boolean = false, delta:int = 0,
                                   commandKey:Boolean = false, controlKey:Boolean = false,
                                   clickCount:int = 0)
		{
            COMPILE::AS3
            {
                super(type, bubbles, cancelable);
            }
            COMPILE::JS
            {
                super(type);
            }
            this.localX = localX;
            this.localY = localY;
            this.relatedObject = relatedObject;
            this.ctrlKey = ctrlKey;
            this.altKey = altKey;
            this.shiftKey = shiftKey;
            this.buttonDown = buttonDown;
            this.delta = delta;
            this.commandKey = commandKey;
            this.controlKey = controlKey;
            this.clickCount = clickCount;
		}

        private var _localX:Number;
        public function get localX():Number
        {
            return _localX;
        }
        public function set localX(value:Number):void
        {
            _localX = value;
            _stagePoint = null;
        }

        private var _localY:Number;
        public function get localY():Number
        {
            return _localY;
        }
        public function set localY(value:Number):void
        {
            _localY = value;
            _stagePoint = null;
        }

        public var relatedObject:Object;
        public var ctrlKey:Boolean;
        public var altKey:Boolean;
        public var shiftKey:Boolean;
        public var buttonDown:Boolean;
        public var delta:int;
        public var commandKey:Boolean;
        public var controlKey:Boolean;
        public var clickCount:int;

        // these map directly to JS MouseEvent fields.
        public function get clientX():Number
        {
            return screenX;
        }
        public function set clientX(value:Number):void
        {
            localX = value;
        }
        public function get clientY():Number
        {
            return screenY;
        }
        public function set clientY(value:Number):void
        {
            localY = value;
        }

        private var _stagePoint:Point;

        public function get screenX():Number
        {
            if (!target) return localX;
            if (!_stagePoint)
            {
                var localPoint:Point = new Point(localX, localY);
                _stagePoint = PointUtils.localToGlobal(localPoint, target);
            }
            return _stagePoint.x;
        }

        public function get screenY():Number
        {
            if (!target) return localY;
            if (!_stagePoint)
            {
                var localPoint:Point = new Point(localX, localY);
                _stagePoint = PointUtils.localToGlobal(localPoint, target);
            }
            return _stagePoint.y;
        }
	}
}

////////////////////////////////////////////////////////////////////////////////
//
//  Licensed to the Apache Software Foundation (ASF) under one or more
//  contributor license agreements.  See the NOTICE file distributed with
//  this work for additional information regarding copyright ownership.
//  The ASF licenses this file to You under the Apache License, Version 2.0
//  (the "License"); you may not use this file except in compliance with
//  the License.  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package org.apache.flex.events
{
    COMPILE::AS3
    {
        import flash.events.MouseEvent;
    }
    COMPILE::JS
    {
        import window.MouseEvent;
    }

    import org.apache.flex.core.IUIBase;
    import org.apache.flex.geom.Point;
    import org.apache.flex.utils.PointUtils;

	/**
	 *  Mouse events
     *
     *  @langversion 3.0
     *  @playerversion Flash 10.2
     *  @playerversion AIR 2.6
     *  @productversion FlexJS 0.0
	 */
	public class MouseEvent extends Event
	{
        private static function platformConstant(s:String):String
        {
            COMPILE::AS3
            {
                return s;
            }
            COMPILE::JS
            {
                return s.toLowerCase();
            }
        }

		public static const MOUSE_DOWN:String = platformConstant("mouseDown");
        public static const MOUSE_MOVE:String = platformConstant("mouseMove");
		public static const MOUSE_UP:String = platformConstant("mouseUp");
		public static const MOUSE_OUT:String = platformConstant("mouseOut");
		public static const MOUSE_OVER:String = platformConstant("mouseOver");
		public static const ROLL_OVER:String = platformConstant("rollOver");
		public static const ROLL_OUT:String = platformConstant("rollOut");
        public static const CLICK:String = "click";

         /**
         *  Constructor.
         *
         *  @param type The name of the event.
         *  @param bubbles Whether the event bubbles.
         *  @param cancelable Whether the event can be canceled.
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion FlexJS 0.0
         */
		public function MouseEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false,
                                   localX:Number = NaN, localY:Number = NaN,
                                   relatedObject:Object = null,
                                   ctrlKey:Boolean = false, altKey:Boolean = false, shiftKey:Boolean = false,
                                   buttonDown:Boolean = false, delta:int = 0,
                                   commandKey:Boolean = false, controlKey:Boolean = false,
                                   clickCount:int = 0)
		{
            COMPILE::AS3
            {
                super(type, bubbles, cancelable);
            }
            COMPILE::JS
            {
                super(type);
            }
            this.localX = localX;
            this.localY = localY;
            this.relatedObject = relatedObject;
            this.ctrlKey = ctrlKey;
            this.altKey = altKey;
            this.shiftKey = shiftKey;
            this.buttonDown = buttonDown;
            this.delta = delta;
            this.commandKey = commandKey;
            this.controlKey = controlKey;
            this.clickCount = clickCount;
		}

        private var _localX:Number;
        public function get localX():Number
        {
            return _localX;
        }
        public function set localX(value:Number):void
        {
            _localX = value;
            _stagePoint = null;
        }

        private var _localY:Number;
        public function get localY():Number
        {
            return _localY;
        }
        public function set localY(value:Number):void
        {
            _localY = value;
            _stagePoint = null;
        }

        public var relatedObject:Object;
        public var ctrlKey:Boolean;
        public var altKey:Boolean;
        public var shiftKey:Boolean;
        public var buttonDown:Boolean;
        public var delta:int;
        public var commandKey:Boolean;
        public var controlKey:Boolean;
        public var clickCount:int;

        // these map directly to JS MouseEvent fields.
        public function get clientX():Number
        {
            return screenX;
        }
        public function set clientX(value:Number):void
        {
            localX = value;
        }
        public function get clientY():Number
        {
            return screenY;
        }
        public function set clientY(value:Number):void
        {
            localY = value;
        }

        private var _stagePoint:Point;

        public function get screenX():Number
        {
            if (!target) return localX;
            if (!_stagePoint)
            {
                var localPoint:Point = new Point(localX, localY);
                _stagePoint = PointUtils.localToGlobal(localPoint, target);
            }
            return _stagePoint.x;
        }

        public function get screenY():Number
        {
            if (!target) return localY;
            if (!_stagePoint)
            {
                var localPoint:Point = new Point(localX, localY);
                _stagePoint = PointUtils.localToGlobal(localPoint, target);
            }
            return _stagePoint.y;
        }

        /**
         * @private
         */
        COMPILE::JS
        private static function installRollOverMixin():Boolean
        {
            window.addEventListener(MOUSE_OVER,
                mouseOverHandler, false);
            return true;
        }

        /**
         * @param e The event.
         * RollOver/RollOut is entirely implemented in mouseOver because
         * when a parent and child share an edge, you only get a mouseout
         * for the child and not the parent and you need to send rollout
         * to both.  A similar issue exists for rollover.
         */
        COMPILE::JS
        private static function mouseOverHandler(e:MouseEvent):void
        {
            var j:int;
            var m:int;
            var outs:Array;
            var me:window.MouseEvent;
            var parent:Object;
            var target:Object = e.target.flexjs_wrapper;
            if (target == null)
                return; // probably over the html tag
            var targets:Array = MouseEvent.targets;
            var index:int = targets.indexOf(target);
            if (index != -1) {
                // get all children
                outs = targets.slice(index + 1);
                m = outs.length;
                for (j = 0; j < m; j++) {
                    me = makeMouseEvent(
                        ROLL_OUT, e);
                    outs[j].element.dispatchEvent(me);
                }
                MouseEvent.targets = targets.slice(0, index + 1);
            }
            else {
                var newTargets:Array = [target];
                if (!('parent' in target))
                    parent = null;
                else
                    parent = target.parent;
                while (parent) {
                    index = targets.indexOf(parent);
                    if (index == -1) {
                        newTargets.unshift(parent);
                        if (!('parent' in parent))
                            break;
                        parent = parent.parent;
                    }
                    else {
                        outs = targets.slice(index + 1);
                        m = outs.length;
                        for (j = 0; j < m; j++) {
                            me = makeMouseEvent(
                                ROLL_OUT, e);
                            outs[j].element.dispatchEvent(me);
                        }
                        targets = targets.slice(0, index + 1);
                        break;
                    }
                }
                var n:int = newTargets.length;
                for (var i:int = 0; i < n; i++) {
                    me = makeMouseEvent(
                        ROLL_OVER, e);
                    newTargets[i].element.dispatchEvent(me);
                }
                MouseEvent.targets = targets.concat(newTargets);
            }
        }

        /**
         */
        COMPILE::JS
        private static var rollOverMixin:Boolean =
            installRollOverMixin();

        /**
         */
        COMPILE::JS
        private static var targets:Array = [];

        /**
         * @param {string} type The event type.
         * @param {Event} e The mouse event.
         * @return {MouseEvent} The new event.
         */
        COMPILE::JS
        private static function makeMouseEvent(type:String, e:window.MouseEvent):window.MouseEvent
        {
            var out:window.MouseEvent = new window.MouseEvent(type);
            out.initMouseEvent(type, false, false,
                e.view, e.detail, e.screenX, e.screenY,
                e.clientX, e.clientY, e.ctrlKey, e.altKey,
                e.shiftKey, e.metaKey, e.button, e.relatedTarget);
            return out;
        };

	}
}

fix rollovers and other mouseevents

fix rollovers and other mouseevents


package classes
{
	/**
	 AGORA - an interactive and web-based argument mapping tool that stimulates reasoning,
	 reflection, critique, deliberation, and creativity in individual argument construction
	 and in collaborative or adversarial settings.
	 Copyright (C) 2011 Georgia Institute of Technology

	 This program is free software: you can redistribute it and/or modify
	 it under the terms of the GNU Affero General Public License as
	 published by the Free Software Foundation, either version 3 of the
	 License, or (at your option) any later version.

	 This program is distributed in the hope that it will be useful,
	 but WITHOUT ANY WARRANTY; without even the implied warranty of
	 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	 GNU Affero General Public License for more details.

	 You should have received a copy of the GNU Affero General Public License
	 along with this program.  If not, see <http://www.gnu.org/licenses/>.

	 */
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.utils.ByteArray;

	import mx.controls.Alert;

	import org.osmf.layout.AbsoluteLayoutFacet;

	public class Language
	{
		//I will set the language to either GERMAN, RUSSIAN or ENGLISH
		//based on this, you could read the values into the variables
		//by default, the language is EN-US

		public static const GERMAN:String = "GER";
		public static const ENGLISH:String = "EN-US";
		public static const RUSSIAN:String = "RUS";
		public static var language:String = ENGLISH;

		public static var xml:XML;
		private static var ready:Boolean=false;

		public static function init():void
		{
			[Embed(source="translation.xml", mimeType="application/octet-stream")]
			const MyData:Class;
			var byteArray:ByteArray = new MyData() as ByteArray;
			var x:XML = new XML(byteArray.readUTFBytes(byteArray.length));
			xml = x;
			ready=true;
		}

		/**The key function. Use this to look up a label from the translation document according to the set language.*/

		public static function lookup(label:String):String{
			if(!ready){
				init();
			}
			trace("Now looking up:" + label);
			var lbl:XMLList = xml.descendants(label);
			var lang:XMLList = lbl.descendants(language);
			var output:String = lang.attribute("text");
			trace("Output is: " + output);
			return output;
		}

	}
}

package classes
{
	/**
	 AGORA - an interactive and web-based argument mapping tool that stimulates reasoning,
	 reflection, critique, deliberation, and creativity in individual argument construction
	 and in collaborative or adversarial settings.
	 Copyright (C) 2011 Georgia Institute of Technology

	 This program is free software: you can redistribute it and/or modify
	 it under the terms of the GNU Affero General Public License as
	 published by the Free Software Foundation, either version 3 of the
	 License, or (at your option) any later version.

	 This program is distributed in the hope that it will be useful,
	 but WITHOUT ANY WARRANTY; without even the implied warranty of
	 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	 GNU Affero General Public License for more details.

	 You should have received a copy of the GNU Affero General Public License
	 along with this program.  If not, see <http://www.gnu.org/licenses/>.

	 */
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.utils.ByteArray;

	import mx.controls.Alert;

	import org.osmf.layout.AbsoluteLayoutFacet;

	public class Language
	{
		//I will set the language to either GERMAN, RUSSIAN or ENGLISH
		//based on this, you could read the values into the variables
		//by default, the language is EN-US

		public static const GERMAN:String = "GER";
		public static const ENGLISH:String = "EN-US";
		public static const RUSSIAN:String = "RUS";
		public static var language:String = ENGLISH;

		public static var xml:XML;
		private static var ready:Boolean=false;

		public static function init():void
		{
			[Embed(source="../../../translation.xml", mimeType="application/octet-stream")]
			const MyData:Class;
			var byteArray:ByteArray = new MyData() as ByteArray;
			var x:XML = new XML(byteArray.readUTFBytes(byteArray.length));
			xml = x;
			ready=true;
		}

		/**The key function. Use this to look up a label from the translation document according to the set language.*/

		public static function lookup(label:String):String{
			if(!ready){
				init();
			}
			trace("Now looking up:" + label);
			var lbl:XMLList = xml.descendants(label);
			var lang:XMLList = lbl.descendants(language);
			var output:String = lang.attribute("text");
			trace("Output is: " + output);
			return output;
		}

	}
}

Fix the transcoding issue. Apparently it was partially cached on the other computer and was erroring on a fresh build.