/*
 * EaselFL is EaselJS rendering to Flash
 * @author Brett Johnson, periscopic.com
 */

/*
* DisplayObject
* Visit http://createjs.com/ for documentation, updates and examples.
*
* Copyright (c) 2010 gskinner.com, inc.
* 
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
* 
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/

/**
* The EaselJS Javascript library provides a retained graphics mode for canvas
* including a full, hierarchical display list, a core interaction model, and
* helper classes to make working with 2D graphics in Canvas much easier.
* @module EaselJS
**/

(function(ns) {

/**
* DisplayObject is an abstract class that should not be constructed directly. Instead construct subclasses such as
* Sprite, Bitmap, and Shape. DisplayObject is the base class for all display classes in the CanvasDisplay library.
* It defines the core properties and methods that are shared between all display objects.
* @class DisplayObject
* @constructor
**/
var DisplayObject = function() {
  this.initialize();
}
var p = DisplayObject.prototype;

	/**
	 * Suppresses errors generated when using features like hitTest, onPress/onClick, and getObjectsUnderPoint with cross
	 * domain content
	 * @property suppressCrossDomainErrors
	 * @static
	 * @type Boolean
	 * @default false
	 **/
	DisplayObject.suppressCrossDomainErrors = false;

	/**
	 * @property _hitTestCanvas
	 * @type HTMLCanvasElement
	 * @static
	 * @protected
	 **/
	/*
	 //-- EaselJS
	DisplayObject._hitTestCanvas = document.createElement("canvas");
	DisplayObject._hitTestCanvas.width = DisplayObject._hitTestCanvas.height = 1;
	*/

	/**
	 * @property _hitTestContext
	 * @type CanvasRenderingContext2D
	 * @static
	 * @protected
	 **/
	/*
	 //-- EaselJS
	DisplayObject._hitTestContext = DisplayObject._hitTestCanvas.getContext("2d");
	*/

	/**
	 * @property _nextCacheID
	 * @type Number
	 * @static
	 * @protected
	 **/
	/*
	 //-- EaselJS
	DisplayObject._nextCacheID = 1;
	*/

	/**
	 * The alpha (transparency) for this display object. 0 is fully transparent, 1 is fully opaque.
	 * @property alpha
	 * @type Number
	 * @default 1
	 **/
	p.alpha = 1;

	/**
	 * If a cache is active, this returns the canvas that holds the cached version of this display object. See cache()
	 * for more information. READ-ONLY.
	 * @property cacheCanvas
	 * @type HTMLCanvasElement
	 * @default null
	 **/
	p.cacheCanvas = null;

	/**
	 * Unique ID for this display object. Makes display objects easier for some uses.
	 * @property id
	 * @type Number
	 * @default -1
	 **/
	p.id = -1;

	/**
	 * Indicates whether to include this object when running Stage.getObjectsUnderPoint(). Setting this to true for
	 * Sprites will cause the Sprite to be returned (not its children) regardless of whether it's mouseChildren property
	 * is true.
	 * @property mouseEnabled
	 * @type Boolean
	 * @default true
	 **/
	p.mouseEnabled = true;

	/**
	 * An optional name for this display object. Included in toString(). Useful for debugging.
	 * @property name
	 * @type String
	 * @default null
	 **/
	p.name = null;

	/**
	 * A reference to the Sprite or Stage object that contains this display object, or null if it has not been added to
	 * one. READ-ONLY.
	 * @property parent
	 * @final
	 * @type DisplayObject
	 * @default null
	 **/
	p.parent = null;

	/**
	 * The x offset for this display object's registration point. For example, to make a 100x100px Bitmap rotate around
	 * it's center, you would set regX and regY to 50.
	 * @property regX
	 * @type Number
	 * @default 0
	 **/
	p.regX = 0;

	/**
	 * The y offset for this display object's registration point. For example, to make a 100x100px Bitmap rotate around
	 * it's center, you would set regX and regY to 50.
	 * @property regY
	 * @type Number
	 * @default 0
	 **/
	p.regY = 0;

	/**
	 * The rotation in degrees for this display object.
	 * @property rotation
	 * @type Number
	 * @default 0
	 **/
	p.rotation = 0;

	/**
	 * The factor to stretch this display object horizontally. For example, setting scaleX to 2 will stretch the display
	 * object to twice it's nominal width.
	 * @property scaleX
	 * @type Number
	 * @default 1
	 **/
	p.scaleX = 1;

	/**
	 * The factor to stretch this display object vertically. For example, setting scaleY to 0.5 will stretch the display
	 * object to half it's nominal height.
	 * @property scaleY
	 * @type Number
	 * @default 1
	 **/
	p.scaleY = 1;

	/**
	 * The factor to skew this display object horizontally.
	 * @property skewX
	 * @type Number
	 * @default 0
	 **/
	p.skewX = 0;

	/**
	 * The factor to skew this display object vertically.
	 * @property skewY
	 * @type Number
	 * @default 0
	 **/
	p.skewY = 0;

	/**
	 * A shadow object that defines the shadow to render on this display object. Set to null to remove a shadow. If
	 * null, this property is inherited from the parent container.
	 * @property shadow
	 * @type Shadow
	 * @default null
	 **/
	p.shadow = null;

	/**
	 * Indicates whether this display object should be rendered to the canvas and included when running
	 * Stage.getObjectsUnderPoint().
	 * @property visible
	 * @type Boolean
	 * @default true
	 **/
	p.visible = true;

	/**
	 * The x (horizontal) position of the display object, relative to its parent.
	 * @property x
	 * @type Number
	 * @default 0
	 **/
	p.x = 0;

	/** The y (vertical) position of the display object, relative to its parent.
	 * @property y
	 * @type Number
	 * @default 0
	 **/
	p.y = 0;

	/**
	 * The composite operation indicates how the pixels of this display object will be composited with the elements
	 * behind it. If null, this property is inherited from the parent container. For more information, read the
	 * <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#compositing">
	 * whatwg spec on compositing</a>.
	 * @property compositeOperation
	 * @type String
	 * @default null
	 **/
	p.compositeOperation = null;

	/**
	 * Indicates whether the display object should have it's x & y position rounded prior to drawing it to stage.
	 * Snapping to whole pixels can result in a sharper and faster draw for images (ex. Bitmap & cached objects).
	 * This only applies if the enclosing stage has snapPixelsEnabled set to true. The snapToPixel property is true
	 * by default for Bitmap and BitmapAnimation instances, and false for all other display objects.
	 * <br/><br/>
	 * Note that this applies only rounds the display object's local position. You should
	 * ensure that all of the display object's ancestors (parent containers) are also on a whole pixel. You can do this
	 * by setting the ancestors' snapToPixel property to true.
	 * @property snapToPixel
	 * @type Boolean
	 * @default false
	 **/
	p.snapToPixel = false;

	/**
	 * The onPress callback is called when the user presses down on their mouse over this display object. The handler
	 * is passed a single param containing the corresponding MouseEvent instance. You can subscribe to the onMouseMove
	 * and onMouseUp callbacks of the event object to receive these events until the user releases the mouse button.
	 * If an onPress handler is set on a container, it will receive the event if any of its children are clicked.
	 * @event onPress
	 * @param {MouseEvent} event MouseEvent with information about the event.
	 **/
	p.onPress = null;

	/**
	 * The onClick callback is called when the user presses down on and then releases the mouse button over this
	 * display object. The handler is passed a single param containing the corresponding MouseEvent instance. If an
	 * onClick handler is set on a container, it will receive the event if any of its children are clicked.
	 * @event onClick
	 * @param {MouseEvent} event MouseEvent with information about the event.
	 **/
	p.onClick = null;

	/**
	 * The onDoubleClick callback is called when the user double clicks over this display object. The handler is
	 * passed a single param containing the corresponding MouseEvent instance. If an onDoubleClick handler is set
	 * on a container, it will receive the event if any of its children are clicked.
	 * @event onDoubleClick
	 * @param {MouseEvent} event MouseEvent with information about the event.
	 **/
	p.onDoubleClick = null;

	/**
	 * The onMouseOver callback is called when the user rolls over the display object. You must enable this event using
	 * stage.enableMouseOver(). The handler is passed a single param containing the corresponding MouseEvent instance.
	 * @event onMouseOver
	 * @param {MouseEvent} event MouseEvent with information about the event.
	 **/
	p.onMouseOver = null;

	/**
	 * The onMouseOut callback is called when the user rolls off of the display object. You must enable this event using
	 * stage.enableMouseOver(). The handler is passed a single param containing the corresponding MouseEvent instance.
	 * @event onMouseOut
	 * @param {MouseEvent} event MouseEvent with information about the event.
	 **/
	p.onMouseOut = null;

	/**
	 * The onTick callback is called on each display object on a stage whenever the stage updates.
	 * This occurs immediately before the rendering (draw) pass.
	 * @event onTick
	 **/
	p.onTick = null;

	/**
	 * An array of Filter objects to apply to this display object. Filters are only applied / updated when cache() or
	 * updateCache() is called on the display object, and only apply to the area that is cached.
	 * @property filters
	 * @type Array[Filter]
	 * @default null
	 **/
	p.filters = null;

	/**
	* Returns an ID number that uniquely identifies the current cache for this display object.
	* This can be used to determine if the cache has changed since a previous check.
	* @property cacheID
	* @type Number
	* @default 0
	*/
	p.cacheID = 0;
	
	/**
	 * A Shape instance that defines a vector mask (clipping path) for this display object.  The shape's transformation
	 * will be applied relative to the display object's parent coordinates (as if it were a child of the parent).
	 * @property mask
	 * @type Shape
	 * @default null
	 */
	p.mask = null;
	
	/**
	 * A display object that will be tested when checking mouse interactions or testing getObjectsUnderPoint. The hit area
	 * will have its transformation applied relative to this display object's coordinate space (as though the hit test object were a child of this
	 * display object and relative to its regX/Y). It is NOT used for hitTest().
	 * @property hitArea
	 * @type DisplayObject
	 * @default null
	 */
	p.hitArea = null;
	

// private properties:

	/**
	 * @property _cacheOffsetX
	 * @protected
	 * @type Number
	 * @default 0
	 **/
	p._cacheOffsetX = 0;

	/**
	 * @property _cacheOffsetY
	 * @protected
	 * @type Number
	 * @default 0
	 **/
	p._cacheOffsetY = 0;

	/**
	* @property _cacheDataURLID
	* @protected
	* @type Number
	* @default 0
	*/
	p._cacheDataURLID = 0;
	
	/**
	* @property _cacheDataURL
	* @protected
	* @type String
	* @default null
	*/
	p._cacheDataURL = null;

	/**
	 * @property _matrix
	 * @protected
	 * @type Matrix2D
	 * @default null
	 **/
	p._matrix = null;
	

// constructor:
	// separated so it can be easily addressed in subclasses:

	/**
	 * Initialization method.
	 * @method initialize
	 * @protected
	*/
	/*
	 //-- EaselJS
	p.initialize = function() {
		this.id = ns.UID.get();
		this._matrix = new ns.Matrix2D();
	}
	*/
	p.initialize = function() {
		this.id = this._flId = ns.UID.get();
		this._matrix = new ns.Matrix2D();
		this._flChange = [];
	}
	

// public methods:
	/**
	 * Returns true or false indicating whether the display object would be visible if drawn to a canvas.
	 * This does not account for whether it would be visible within the boundaries of the stage.
	 * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
	 * @method isVisible
	 * @return {Boolean} Boolean indicating whether the display object would be visible if drawn to a canvas
	 **/
	p.isVisible = function() {
		return this.visible && this.alpha > 0 && this.scaleX != 0 && this.scaleY != 0;
	}

	/**
	 * Draws the display object into the specified context ignoring it's visible, alpha, shadow, and transform.
	 * Returns true if the draw was handled (useful for overriding functionality).
	 * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
	 * @method draw
	 * @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into.
	 * @param {Boolean} ignoreCache Indicates whether the draw operation should ignore any current cache.
	 * For example, used for drawing the cache (to prevent it from simply drawing an existing cache back
	 * into itself).
	 **/
	/*
	 //-- EaselJS
	p.draw = function(ctx, ignoreCache) {
		if (ignoreCache || !this.cacheCanvas) { return false; }
		ctx.drawImage(this.cacheCanvas, this._cacheOffsetX, this._cacheOffsetY);
		return true;
	}
	*/
	p.draw = function(ctx, ignoreCache) {
		this._flSyncProps(ctx);
		
		if(this._flChange.length){
			for(var i=0, l=this._flChange.length; i<l; ++i) {
				ctx._flChange.push(this._flChange[i]);
			}
			this._flChange = [];
		}
	}
	
	/**
	 * Applies this display object's transformation, alpha, globalCompositeOperation, clipping path (mask), and shadow to the specified
	 * context. This is typically called prior to draw.
	 * @method setupContext
	 * @param {CanvasRenderingContext2D} ctx The canvas 2D to update.
	 **/
	/*
	 //-- EaselJS
	p.updateContext = function(ctx) {
		var mtx, mask=this.mask, o=this;
		
		if (mask && mask.graphics) {
			mtx = mask.getMatrix(mask._matrix);
			ctx.transform(mtx.a,  mtx.b, mtx.c, mtx.d, mtx.tx, mtx.ty);
			
			mask.graphics.drawAsPath(ctx);
			ctx.clip();
			
			mtx.invert();
			ctx.transform(mtx.a,  mtx.b, mtx.c, mtx.d, mtx.tx, mtx.ty);
		}
		
		mtx = o._matrix.identity().appendTransform(o.x, o.y, o.scaleX, o.scaleY, o.rotation, o.skewX, o.skewY, o.regX, o.regY);
		if (ns.Stage._snapToPixelEnabled && o.snapToPixel) { ctx.transform(mtx.a,  mtx.b, mtx.c, mtx.d, mtx.tx+0.5|0, mtx.ty+0.5|0); }
		else { ctx.transform(mtx.a,  mtx.b, mtx.c, mtx.d, mtx.tx, mtx.ty); }
		ctx.globalAlpha *= o.alpha;
		if (o.compositeOperation) { ctx.globalCompositeOperation = o.compositeOperation; }
		if (o.shadow) { this._applyShadow(ctx, o.shadow); }
	}
	*/
	p.updateContext = function(ctx) {
		if(ns.Stage.FL_THROW_UNIMPLEMENTED) throw "EaselFl::DisplayObject.updateContext not yet implemented";
	}

	/**
	 * Draws the display object into a new canvas, which is then used for subsequent draws. For complex content
	 * that does not change frequently (ex. a Sprite with many children that do not move, or a complex vector Shape),
	 * this can provide for much faster rendering because the content does not need to be re-rendered each tick. The
	 * cached display object can be moved, rotated, faded, etc freely, however if it's content changes, you must manually
	 * update the cache by calling updateCache() or cache() again. You must specify the cache area via the x, y, w,
	 * and h parameters. This defines the rectangle that will be rendered and cached using this display object's
	 * coordinates. For example if you defined a Shape that drew a circle at 0, 0 with a radius of 25, you could call
	 * myShape.cache(-25, -25, 50, 50) to cache the full shape.
	 * @method cache
	 * @param {Number} x The x coordinate origin for the cache region.
	 * @param {Number} y The y coordinate origin for the cache region.
	 * @param {Number} width The width of the cache region.
	 * @param {Number} height The height of the cache region.
	 **/
	/*
	 //-- EaselJS
	p.cache = function(x, y, width, height) {
		// draw to canvas.
		var cacheCanvas = this.cacheCanvas;
		if (cacheCanvas == null) { cacheCanvas = this.cacheCanvas = document.createElement("canvas"); }
		var ctx = cacheCanvas.getContext("2d");
		cacheCanvas.width = width;
		cacheCanvas.height = height;
		ctx.setTransform(1, 0, 0, 1, -x, -y);
		ctx.clearRect(x, y, cacheCanvas.width, cacheCanvas.height); // some browsers don't clear correctly.
		this.draw(ctx, true, this._matrix.reinitialize(1,0,0,1,-x,-y)); // containers require the matrix to work from
		this._cacheOffsetX = x;
		this._cacheOffsetY = y;
		this._applyFilters();
		this.cacheID = DisplayObject._nextCacheID++;
	}
	*/
	p.cache = function(x, y, width, height) {
	  //-- In EaselFl cache currently only prevents redraw & applies filters
	  this._flCache = true;
	  this._flCached = false;
		this._flFiltersDirty = true;
	}

	/**
	 * Redraws the display object to its cache. Calling updateCache without an active cache will throw an error.
	 * If compositeOperation is null the current cache will be cleared prior to drawing. Otherwise the display object
	 * will be drawn over the existing cache using the specified compositeOperation.
	 * @method updateCache
	 * @param {String} compositeOperation The compositeOperation to use, or null to clear the cache and redraw it.
	 * <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#compositing">
	 * whatwg spec on compositing</a>.
	 **/
	/*
	 //-- EaselJS
	p.updateCache = function(compositeOperation) {
		var cacheCanvas = this.cacheCanvas, offX = this._cacheOffsetX, offY = this._cacheOffsetY;
		if (cacheCanvas == null) { throw "cache() must be called before updateCache()"; }
		var ctx = cacheCanvas.getContext("2d");
		ctx.setTransform(1, 0, 0, 1, -offX, -offY);
		if (!compositeOperation) {
			ctx.clearRect(offX, offY, cacheCanvas.width, cacheCanvas.height);
		} else { ctx.globalCompositeOperation = compositeOperation; }
		this.draw(ctx, true);
		if (compositeOperation) { ctx.globalCompositeOperation = "source-over"; }
		this._applyFilters();
		this.cacheID = DisplayObject._nextCacheID++;
	}
	*/
	p.updateCache = function(compositeOperation) {
		//-- In EaselFl cache currently only prevents redraw and updates filters
		this._flCache = true;
		this._flCached = false;
		this._flFiltersDirty = true;
	}

	/**
	 * Clears the current cache. See cache() for more information.
	 * @method uncache
	 **/
	/*
	 //-- EaselJS
	p.uncache = function() {
		this._cacheDataURL = this.cacheCanvas = null;
		this.cacheID = this._cacheOffsetX = this._cacheOffsetY = 0;
	}
	*/
	p.uncache = function() {
	  this._flCache = this._flCached = false;
	}
	
	/**
	* Returns a data URL for the cache, or null if this display object is not cached.
	* Uses cacheID to ensure a new data URL is not generated if the cache has not changed.
	* @method getCacheDataURL.
	**/
	/*
	 //-- EaselJS
	 p.getCacheDataURL = function() {
		if (!this.cacheCanvas) { return null; }
		if (this.cacheID != this._cacheDataURLID) { this._cacheDataURL = this.cacheCanvas.toDataURL(); }
		return this._cacheDataURL;
	}
	*/
	p.getCacheDataURL = function() {
		if(ns.Stage.FL_THROW_UNIMPLEMENTED) throw "EaselFl::DisplayObject.getCacheDataURL not yet implemented";
	}
	
	/**
	 * Returns the stage that this display object will be rendered on, or null if it has not been added to one.
	 * @method getStage
	 * @return {Stage} The Stage instance that the display object is a descendent of. null if the DisplayObject has not
	 * been added to a Stage.
	 **/
	p.getStage = function() {
		var o = this;
		while (o.parent) {
			o = o.parent;
		}
		if (o instanceof ns.Stage) { return o; }
		return null;
	}

	/**
	 * Transforms the specified x and y position from the coordinate space of the display object
	 * to the global (stage) coordinate space. For example, this could be used to position an HTML label
	 * over a specific point on a nested display object. Returns a Point instance with x and y properties
	 * correlating to the transformed coordinates on the stage.
	 * @method localToGlobal
	 * @param {Number} x The x position in the source display object to transform.
	 * @param {Number} y The y position in the source display object to transform.
	 * @return {Point} A Point instance with x and y properties correlating to the transformed coordinates
	 * on the stage.
	 **/
	p.localToGlobal = function(x, y) {
		var mtx = this.getConcatenatedMatrix(this._matrix);
		if (mtx == null) { return null; }
		mtx.append(1, 0, 0, 1, x, y);
		return new ns.Point(mtx.tx, mtx.ty);
	}

	/**
	 * Transforms the specified x and y position from the global (stage) coordinate space to the
	 * coordinate space of the display object. For example, this could be used to determine
	 * the current mouse position within the display object. Returns a Point instance with x and y properties
	 * correlating to the transformed position in the display object's coordinate space.
	 * @method globalToLocal
	 * @param {Number} x The x position on the stage to transform.
	 * @param {Number} y The y position on the stage to transform.
	 * @return {Point} A Point instance with x and y properties correlating to the transformed position in the
	 * display object's coordinate space.
	 **/
	p.globalToLocal = function(x, y) {
		var mtx = this.getConcatenatedMatrix(this._matrix);
		if (mtx == null) { return null; }
		mtx.invert();
		mtx.append(1, 0, 0, 1, x, y);
		return new ns.Point(mtx.tx, mtx.ty);
	}

	/**
	 * Transforms the specified x and y position from the coordinate space of this display object to the
	 * coordinate space of the target display object. Returns a Point instance with x and y properties
	 * correlating to the transformed position in the target's coordinate space. Effectively the same as calling
	 * var pt = this.localToGlobal(x, y); pt = target.globalToLocal(pt.x, pt.y);
	 * @method localToLocal
	 * @param {Number} x The x position in the source display object to transform.
	 * @param {Number} y The y position on the stage to transform.
	 * @param {DisplayObject} target The target display object to which the coordinates will be transformed.
	 * @return {Point} Returns a Point instance with x and y properties correlating to the transformed position
	 * in the target's coordinate space.
	 **/
	p.localToLocal = function(x, y, target) {
		var pt = this.localToGlobal(x, y);
		return target.globalToLocal(pt.x, pt.y);
	}

	/**
	 * Shortcut method to quickly set the transform properties on the display object. All parameters are optional.
	 * Omitted parameters will have the default value set (ex. 0 for x/y, 1 for scaleX/Y).
	 * @method setTransform
	 * @param {Number} x
	 * @param {Number} y
	 * @param {Number} scaleX
	 * @param {Number} scaleY
	 * @param {Number} rotation
	 * @param {Number} skewX
	 * @param {Number} skewY
	 * @param {Number} regX
	 * @param {Number} regY
	*/
	p.setTransform = function(x, y, scaleX, scaleY, rotation, skewX, skewY, regX, regY) {
		this.x = x || 0;
		this.y = y || 0;
		this.scaleX = scaleX == null ? 1 : scaleX;
		this.scaleY = scaleY == null ? 1 : scaleY;
		this.rotation = rotation || 0;
		this.skewX = skewX || 0;
		this.skewY = skewY || 0;
		this.regX = regX || 0;
		this.regY = regY || 0;
	}

	/**
	 * Returns a matrix based on this object's transform.
	 * @method getMatrix
	 * @param {Matrix2D} matrix Optional. A Matrix2D object to populate with the calculated values. If null, a new
	 * Matrix object is returned.
	 * @return {Matrix2D} A matrix representing this display object's transform.
	 **/
	p.getMatrix = function(matrix) {
		var o = this;
		return (matrix ? matrix.identity() : new ns.Matrix2D()).appendTransform(o.x, o.y, o.scaleX, o.scaleY, o.rotation, o.skewX, o.skewY, o.regX, o.regY).appendProperties(o.alpha, o.shadow, o.compositeOperation);
	}
	
	/**
	 * Generates a concatenated Matrix2D object representing the combined transform of
	 * the display object and all of its parent Containers up to the highest level ancestor
	 * (usually the stage). This can be used to transform positions between coordinate spaces,
	 * such as with localToGlobal and globalToLocal.
	 * @method getConcatenatedMatrix
	 * @param {Matrix2D} mtx Optional. A Matrix2D object to populate with the calculated values. If null, a new
	 * Matrix object is returned.
	 * @return {Matrix2D} a concatenated Matrix2D object representing the combined transform of
	 * the display object and all of its parent Containers up to the highest level ancestor (usually the stage).
	 **/
	p.getConcatenatedMatrix = function(matrix) {
		if (matrix) { matrix.identity(); }
		else { matrix = new ns.Matrix2D(); }
		var o = this;
		while (o != null) {
			matrix.prependTransform(o.x, o.y, o.scaleX, o.scaleY, o.rotation, o.skewX, o.skewY, o.regX, o.regY).prependProperties(o.alpha, o.shadow, o.compositeOperation);
			o = o.parent;
		}
		return matrix;
	}

	/**
	 * Tests whether the display object intersects the specified local point (ie. draws a pixel with alpha > 0 at
	 * the specified position). This ignores the alpha, shadow and compositeOperation of the display object, and all
	 * transform properties including regX/Y.
	 * @method hitTest
	 * @param {Number} x The x position to check in the display object's local coordinates.
	 * @param {Number} y The y position to check in the display object's local coordinates.
	 * @return {Boolean} A Boolean indicting whether a visible portion of the DisplayObject intersect the specified
	 * local Point.
	*/
	/*
	 //-- EaselJS
	p.hitTest = function(x, y) {
		var ctx = DisplayObject._hitTestContext;
		var canvas = DisplayObject._hitTestCanvas;

		ctx.setTransform(1,  0, 0, 1, -x, -y);
		this.draw(ctx);

		var hit = this._testHit(ctx);

		canvas.width = 0;
		canvas.width = 1;
		return hit;
	}
	*/
	p.hitTest = function(x, y) {
		if(this._flCtx){
		 var val =  this._flCtx.flInvoke (this.id, 'htp', [x, y]);
		  return val;
		}
		return false;
	}
	
	/**
	 * Returns a clone of this DisplayObject. Some properties that are specific to this instance's current context are
	 * reverted to their defaults (for example .parent).
	 * @method clone
	 @return {DisplayObject} A clone of the current DisplayObject instance.
	 **/
	/*
	 //-- EaselJS
	 p.clone = function() {
		var o = new DisplayObject();
		this.cloneProps(o);
		return o;
	}
	*/
	p.clone = function() {
		if(ns.Stage.FL_THROW_UNIMPLEMENTED) throw "EaselFl::DisplayObject.clone not yet implemented";
		return false;
	}

	/**
	 * Returns a string representation of this object.
	 * @method toString
	 * @return {String} a string representation of the instance.
	 **/
	p.toString = function() {
		return "[DisplayObject (name="+  this.name +")]";
	}

// private methods:


	/**
	 * @method _applyFilters
	 * @protected
	 **/
	/*
	 //-- EaselJS
	 p._applyFilters = function() {
		if (!this.filters || this.filters.length == 0 || !this.cacheCanvas) { return; }
		var l = this.filters.length;
		var ctx = this.cacheCanvas.getContext("2d");
		var w = this.cacheCanvas.width;
		var h = this.cacheCanvas.height;
		for (var i=0; i<l; i++) {
			this.filters[i].applyFilter(ctx, 0, 0, w, h);
		}
	}
	*/

	// separated so it can be used more easily in subclasses:
	/**
	 * @method cloneProps
	 * @protected
	 * @param {DisplayObject} o The DisplayObject instance which will have properties from the current DisplayObject
	 * instance copied into.
	 **/
	/*
	 //-- EaselJS
	p.cloneProps = function(o) {
		o.alpha = this.alpha;
		o.name = this.name;
		o.regX = this.regX;
		o.regY = this.regY;
		o.rotation = this.rotation;
		o.scaleX = this.scaleX;
		o.scaleY = this.scaleY;
		o.shadow = this.shadow;
		o.skewX = this.skewX;
		o.skewY = this.skewY;
		o.visible = this.visible;
		o.x  = this.x;
		o.y = this.y;
		o.mouseEnabled = this.mouseEnabled;
		o.compositeOperation = this.compositeOperation;
		if (this.cacheCanvas) {
			o.cacheCanvas = this.cacheCanvas.cloneNode(true);
			o.cacheCanvas.getContext("2d").putImageData(this.cacheCanvas.getContext("2d").getImageData(0,0,this.cacheCanvas.width,this.cacheCanvas.height),0,0);
		}
	}
	*/
	p.cloneProps = function(o) {
		o.alpha = this.alpha;
		o.name = this.name;
		o.regX = this.regX;
		o.regY = this.regY;
		o.rotation = this.rotation;
		o.scaleX = this.scaleX;
		o.scaleY = this.scaleY;
		o.shadow = this.shadow;
		o.skewX = this.skewX;
		o.skewY = this.skewY;
		o.visible = this.visible;
		o.x  = this.x;
		o.y = this.y;
		o.mouseEnabled = this.mouseEnabled;
		o.compositeOperation = this.compositeOperation;
	
		o._flCache = this._flCache;
	}

	/**
	 * @method _applyShadow
	 * @protected
	 * @param {CanvasRenderingContext2D} ctx
	 * @param {Shadow} shadow
	 **/
	/*
	 //-- EaselJS
	 p._applyShadow = function(ctx, shadow) {
		shadow = shadow || Shadow.identity;
		ctx.shadowColor = shadow.color;
		ctx.shadowOffsetX = shadow.offsetX;
		ctx.shadowOffsetY = shadow.offsetY;
		ctx.shadowBlur = shadow.blur;
	}
	*/
	
	/**
	 * @method _tick
	 * @protected
	 **/
	p._tick = function(data) {
		if (this.onTick) { this.onTick(data); }
	}

	/**
	 * @method _testHit
	 * @protected
	 * @param {CanvasRenderingContext2D} ctx
	 * @return {Boolean}
	 **/
	/*
	 //-- EaselJS
	 p._testHit = function(ctx) {
		try {
			var hit = ctx.getImageData(0, 0, 1, 1).data[3] > 1;
		} catch (e) {
			if (!DisplayObject.suppressCrossDomainErrors) {
				throw "An error has occurred. This is most likely due to security restrictions on reading canvas pixel data with local or cross-domain images.";
			}
		}
		return hit;
	}
	*/

	
	/**** Begin EaselFL specific code ****/

	/**
	 * Identical to id, but
	 * private, as .id tends
	 * to be overwritten and 
	 * is crucial.
	 * @type {Number}
	 */
	p._flId = -1;

	/**
	 * The number of references to
	 * this object which require that
	 * it is retained within the flash
	 * rendering context.
	 */
	p._flRefs = 0;

	 /**
	 * The ContextFl of the display list to which this is attached
	 * @private
	 **/
	p._flCtx = null;
	
	/**
	 * The synced X value
	 * @private
	 * @property _flX
	 * @type Number
	 **/
	p._flX = 0;
	
	/**
	 * The synced y value
	 * @private
	 * @property _flY
	 * @type Number
	 **/
	p._flY = 0;
	
	/**
	 * The synced scaleX value
	 * @private
	 * @property _flScaleX
	 * @type Number
	 **/
	p._flScaleX = 1;
	
	/**
	 * The synced scaleY value
	 * @private
	 * @property _flScaleY
	 * @type Number
	 **/
	p._flScaleY = 1;
	
	/**
	 * The synced rotation value
	 * @private
	 * @property _flRotation
	 * @type Number
	 **/
	p._flRotation = 0;
	
	/**
	 * The synced skewX value
	 * @private
	 * @property _flSkewX
	 * @type Number
	 **/
	p._flSkewX = 0;
	
	/**
	 * The synced skewY value
	 * @private
	 * @property _flSkewY
	 * @type Number
	 **/
	p._flSkewY = 0;
	
	/**
	 * The synced regX value
	 * @private
	 * @property _flRegX
	 * @type Number
	 **/
	p._flRegX = 0;
	
	/**
	 * The synced regY value
	 * @private
	 * @property _flRegX
	 * @type Number
	 **/
	p._flRegY = 0;
	
	/**
	 * The synced visible value
	 * @private
	 * @property _flVisible
	 * @type Boolean
	 **/
	p._flVisible = true;
	
	/**
	 * The synced alpha value
	 * @private
	 * @property _flAlpha
	 * @type Number
	 **/
	p._flAlpha = 1;
	
	/**
	 * The synced mouseEnabled value
	 * @private
	 * @property _flMouseEnabled
	 * @type Number
	 **/
	p._flMouseEnabled = true;
	
	/**
	 * The synced onMouseOver method
	 * @private
	 * @property _flMouseOver
	 * @type function
	 **/
	p._flMouseOver = null;
	
	/**
	 * The synced onMouseOut method
	 * @private
	 * @property _flMouseOut
	 * @type function
	 **/
	p._flMouseOut = null;
	
	/**
	 * The synced onClick method
	 * @private
	 * @property _flClick
	 * @type function
	 **/
	p._flClick = null;
	
	/**
	 * The synced onPress method
	 * @private
	 * @property _flPress
	 * @type function
	 **/
	p._flPress = null;
	
	/**
	 * The synced mask display object
	 * @private
	 * @property _flMask
	 * @type DisplayObject
	 **/
	p._flMask = null;
	
	
	//TODO : figure out if shadow sync is used
	p._flShadow = null;
	
	/**
	 * NOTE : not part of the original EaselJS api
	 * The synced useHandCursor value
	 * @private
	 * @property _flUseHandCursor
	 * @type Boolean
	 **/
	p._flUseHandCursor = false;
	
	/**
	 * NOTE : not part of the original EaselJS api
	 * The synced buttonMode value
	 * @private
	 * @property _flButtonMode
	 * @type Boolean
	 **/
	p._flButtonMode = false;
	
	/**
	 * Commands that will be pushed to Flash on each render cycle when this
	 * is in the display list.
	 * @private
	 * @property _flChange
	 * @type Array
	 **/
	p._flChange = null;
	
	/**
	 * Whether to this should be cached
	 * @private
	 * @property _flCache
	 * @type Boolean
	 **/
	p._flCache = false;
	
	/**
	 * Whether this is cached
	 * @private
	 * @property _flCached
	 * @type Boolean
	 **/
	p._flCached = false;
	
	/**
	 * Whether filters array is invalidated
	 * @private
	 * @property _flFiltersDirty
	 * @type Boolean
	 **/
	p._flFiltersDirty = false;


	/**
	 * Filters that have been synced.
	 * @private
	 * @property {_flFilters}
	 * @type {Array}
	 */
	p._flFilters = null;

	/**
	 * Resets comparison props to default values and removes this 
	 * object from the Flash rendering context. Called when
	 * an object is removed from Flash rendering context for memory
	 * managment purposes.
	 * @return {Void}
	 */
	p._flResetProps = function() {
		this._flVisible = true;

		this._flX = 
		this._flY = 
		this._flRotation =
		this._flRegX =
		this._flRegY = 
		this._flSkewX =
		this._flSkeyY = 0;
		
		this._flAlpha =
		this._flScaleX = 
		this._flScaleY = 1;

		this._flChange = [];

		this._flCtx = 
		this._flShadow = 
		this._flClick =
		this._flPress = 
		this._flMask = 
		this._flMouseOver =
		this._flMouseOut =
		this._flMouseEnabled = null;

		this._flCache = 
		this._flCached = 
		this._flFiltersDirty = //?
		this._flUseHandCursor =
		this._flButtonMode = false;
	}

	/**
	 * @method _flSyncProps
	 * @protected
	 * @param ContextFl
	 **/
	p._flSyncProps = function(ctx) {

		//-- Synchronize Visibility		
		if( this.visible !== this._flVisible) {			
			this._flVisible = this.visible;
			this._flChange.push([this._flId, 'vs', this.visible]);
		}
		
		//don't sync anything else if not visible
		if(!this.visible) {
		  return;
		}			
		
		//synchronize mouse enabled
		if(this.mouseEnabled!==this._flMouseEnabled){
		  this._flMouseEnabled = this.mouseEnabled;
		  this._flChange.push([this._flId, 'smen', this.mouseEnabled]);
		}
		
		if(this.mouseEnabled) {
		  //synchronize mouse events
		  if(this.onMouseOver!==this._flMouseOver) {
				if(this.onMouseOver  && !this._flMouseOver) {
					this._flChange.push([this._flId, 'amov']);
				}else if(!this.onMouseOver && this._flMouseOver) {
					this._flChange.push([this._flId, 'rmov']);
				}				
				this._flMouseOver = this.onMouseOver;
		  }
			
		  if(this.onMouseOut!==this._flMouseOut) {
				if(this.onMouseOut  && !this._flMouseOut) {
					this._flChange.push([this._flId, 'amot']);
				}else if(!this.onMouseOut && this._flMouseOut) {
					this._flChange.push([this._flId, 'rmot']);
				}
			  this._flMouseOut = this.onMouseOut;
		  }
			
		  if(this.onClick!==this._flClick) {
				if(this.onClick  && !this._flClick) {
					this._flChange.push([this._flId, 'amck']);
				}else if(!this.onClick && this._flClick) {
					this._flChange.push([this._flId, 'rmck']);
				}
			  this._flClick = this.onClick;
		  }
			
			
			if(this.onPress!==this._flOnPress) {
				if(this.onPress  && !this._flOnPress) {
					this._flChange.push([this._flId, 'aprs']);
				}else if(!this.onPress && this._flOnPress) {
					this._flChange.push([this._flId, 'rprs']);
				}
			  this._flOnPress = this.onPress;
		  }
		}
		
		//-- Synchronize Alpha
		if( this.alpha !== this._flAlpha) {
			this._flAlpha = this.alpha;
			this._flChange.push([this._flId, 'op', this.alpha]);
		}
		
		//-- Synchronize Shadow
		if( this.shadow !== this._flShadow) {
			if(this._flShadow) {
				this._flShadow._flDeretain();
			}

			this._flShadow = this.shadow;

			if(this._flShadow) {
				this._flShadow._flRetain(ctx);
			} 
			
			this._flChange.push([this._flId, 'shd', this._flShadow ?  this._flShadow._flId : null]);	
		}
		
		//-- Synchronize Shadow properties
		if(this.shadow) {
			this.shadow._flSyncProps();
		}

		//-- Synchronize Filters
		if(this._flFiltersDirty) {
			var filterIDs, i, l;

			this._flFiltersDirty=false;

			if(this._flFilters) {
				for (i = 0, l = this._flFilters.length; i<l; ++i) {
					this._flFilters[i]._flDeretain();
				}
				this._flFilters = null;
			}
			
			if(this.filters && this.filters.length>0) {	

				filterIDs = [];
	
				for (i=0, l=this.filters.length; i<l; i++) {
					var flt = this.filters[i];
					flt._flRetain(ctx);
					flt._flSyncProps(ctx);
					filterIDs[i] = flt._flId;
				}

				this._flFilters = this.filters.slice(0); //clone
				this._flChange.push([this._flId, 'flts', filterIDs]);
			}
		}

		//-- Synchronize Mask
		if(this.mask !== this._flMask) {
			if(this._flMask) {
				this._flMask._flDeretain();
			}

			this._flMask = this.mask;

			if(this._flMask) {
				this._flMask._flRetain(ctx);
			}
			
			this._flChange.push([this._flId, 'msk', this.mask ? this.mask._flId : null]);
		}

		//-- Synchronize Mask properties
		if(this._flMask) {
			this._flMask.draw(ctx);
		}

		//-- Synchronize tranform
		if(	this.x !== this._flX ||
			this.y !== this._flY ||
			this.scaleX !== this._flScaleX ||
			this.scaleY !== this._flScaleY ||
			this.rotation !== this._flRotation ||
			this.skewX !== this._flSkewX ||
			this.skewY !== this._flSkewY ||
			this.regX !== this._flRegX ||
			this.regY !== this._flRegY ) {
			
			this._flX = this.x;
			this._flY = this.y;
			this._flScaleX = this.scaleX;
			this._flScaleY = this.scaleY;
			this._flRotation = this.rotation;
			this._flSkewX = this.skewX;
			this._flSkewY = this.skewY;
			this._flRegX = this.regX;
			this._flRegY = this.regY;
			
			var mtx = DisplayObject._flTempMtx;
			mtx.identity(); //reset
			mtx.prependTransform( this.x, this.y, this.scaleX, this.scaleY, this.rotation, this.skewX, this.skewY, this.regX, this.regY);
			
			this._flChange.push([this._flId, 'mtx', [mtx.a, mtx.b, mtx.c, mtx.d, mtx.tx, mtx.ty]]);
		}
	}
	

	/**
	 * Increment the number of references 
	 * on this and dependent objects.
	 */
	p._flRetain = function(ctx) {
		this._flRefs += 1;
		
		if(!this._flCtx) {
			this._flRunCreate(ctx);
		}

		if(this._flMask) {
			this._flMask._flRetain();
		}

		if(this._flShadow) {
			this._flShadow._flRetain();
		}

		if(this._flFilters) {
			for (var i = 0, l = this._flFilters.length; i<l; ++i) {
			    this._flFilters[i]._flRetain();
			}
		}
	}

	/**
	 * Decrement the number of references 
	 * on this and dependent objects.
	 */
	p._flDeretain = function() {
		this._flRefs -= 1;

		if(this._flMask) {
			this._flMask._flDeretain();
		}

		if(this._flShadow) {
			this._flShadow._flDeretain();
		}

		if(this._flFilters) {
			for (var i = 0, l = this._flFilters.length; i<l; ++i) {
			    this._flFilters[i]._flDeretain();
			}
		}

		// can display objects ever have more than 1 ref?
		//if(this._flRefs===0) {
		//	this._flCtx = null;
		//}
	}

	
	/**
	 * Add the creation command for this object and its children to the CanvasFl context, to be created in Flash
	 **/
	p._flRunCreate = function(ctx){
		this._flCtx = ctx;
		ctx._flCreate.push([this._flType, this]);
	}
	
	//-- Set usage of hand cursor
	//-- Not part of the original EaselJS api
	p.flSetCursorMode = function(useHandCursor, buttonMode) {
		if(useHandCursor !== this._flUseHandCursor) {
		  this._flChange.push([this._flId, 'scrs', useHandCursor]);
		  this._flUseHandCursor = useHandCursor;
		}
		
		if(buttonMode !== this._flButtonMode) {
		  this._flChange.push([this._flId, 'sbtn', buttonMode]);
		  this._flButtonMode = buttonMode;
		}
	}
	
	//-- Static
	/**
	 * Matrix2D for reuse
	 * @static
	 * @protected
	 * @type Matrix2D
	 **/
	DisplayObject._flTempMtx = new ns.Matrix2D();

	/**** End EaselFL specific code ****/
	
ns.DisplayObject = DisplayObject;
}(createjs||(createjs={})));
var createjs;