package citrus.objects {

	import ash.signals.Signal2;
	import ash.signals.Signal3;
	import ash.signals.SignalAny;

	import citrus.core.CitrusObject;
	import citrus.math.MathVector;
	import citrus.view.ICitrusArt;
	import citrus.view.ISpriteView;
	import citrus.view.starlingview.StarlingSpriteDebugArt;

	import flash.utils.Dictionary;

	/**
	 * This is the primary class for creating graphical game objects.
	 * You should override this class to create a visible game object such as a Spaceship, Hero, or Backgrounds. This is the equivalent
	 * of the Flash Sprite. It has common properties that are required for properly displaying and
	 * positioning objects. You can also add your logic to this sprite.
	 * 
	 * <p>With a CitrusSprite, there is only simple collision and velocity logic. If you'd like to take advantage of Box2D or Nape physics,
	 * you should extend the APhysicsObject class instead.</p>
	 */	
	public class CitrusSprite extends CitrusObject implements ISpriteView
	{
		public var collisions:Dictionary = new Dictionary();
		
		public var onCollide:SignalAny = new SignalAny(CitrusSprite, CitrusSprite, MathVector, Number);
		public var onPersist:Signal3 = new Signal3(CitrusSprite, CitrusSprite, MathVector);
		public var onSeparate:Signal2 = new Signal2(CitrusSprite, CitrusSprite);
		
		protected var _x:Number = 0;
		protected var _y:Number = 0;
		protected var _width:Number = 30;
		protected var _height:Number = 30;
		protected var _velocity:MathVector = new MathVector();
		protected var _parallaxX:Number = 1;
		protected var _parallaxY:Number = 1;
		protected var _rotation:Number = 0;
		protected var _group:uint = 0;
		protected var _visible:Boolean = true;
		protected var _touchable:Boolean = false;
		protected var _mouseChildren:Boolean = false;
		protected var _view:* = StarlingSpriteDebugArt;
		protected var _art:ICitrusArt;
		protected var _inverted:Boolean = false;
		protected var _animation:String = "";
		protected var _offsetX:Number = 0;
		protected var _offsetY:Number = 0;
		protected var _registration:String = "topLeft";
			
		public function CitrusSprite(params:Object = null)
		{
			
			super(params);
		}
		
		/**
		 * @inheritDoc
		 */
		public function handleArtReady(citrusArt:ICitrusArt):void {	
			_art = citrusArt;
		}
		
		/**
		 * @inheritDoc
		 */
		public function handleArtChanged(oldArt:ICitrusArt):void {	
		}
		
		override public function destroy():void
		{
			onCollide.removeAll();
			onPersist.removeAll();
			onSeparate.removeAll();
			collisions = null;
			_art = null;
			
			super.destroy();
		}
		
		/**
		 * No physics here, return <code>null</code>.
		 */ 
		public function getBody():* {
			return null;
		}
		
		public function get x():Number
		{
			return _x;
		}
		
		public function set x(value:Number):void
		{
			_x = value;
		}
		
		public function get y():Number
		{
			return _y;
		}
		
		public function set y(value:Number):void
		{
			_y = value;
		}
		
		public function get z():Number {
			return 0;
		}
		
		public function get width():Number
		{
			return _width;
		}
		
		public function set width(value:Number):void
		{
			_width = value;
		}
		
		public function get height():Number
		{
			return _height;
		}
		
		public function set height(value:Number):void
		{
			_height = value;
		}
		
		public function get depth():Number {
			return 0;
		}
		
		public function get velocity():Array {
			return [_velocity.x, _velocity.y, 0];
		}
		
		public function set velocity(value:Array):void {
			
			_velocity.x = value[0];
			_velocity.y = value[1];
		}
		
		public function get parallaxX():Number
		{
			return _parallaxX;
		}
		
		[Inspectable(defaultValue="1")]
		public function set parallaxX(value:Number):void
		{
			_parallaxX = value;
		}
		
		public function get parallaxY():Number
		{
			return _parallaxY;
		}
		
		[Inspectable(defaultValue="1")]
		public function set parallaxY(value:Number):void
		{
			_parallaxY = value;
		}
		
		public function get rotation():Number
		{
			return _rotation;
		}
		
		public function set rotation(value:Number):void
		{
			_rotation = value;
		}
		
		/**
		 * The group is similar to a z-index sorting. Default is 0, 1 is over.
		 */
		public function get group():uint
		{
			return _group;
		}
		
		[Inspectable(defaultValue="0")]
		public function set group(value:uint):void
		{
			_group = value;
		}
		
		public function get visible():Boolean
		{
			return _visible;
		}
		
		public function set visible(value:Boolean):void
		{
			_visible = value;
		}
		
		public function get touchable():Boolean
		{
			return _touchable;
		}
		
		public function set touchable(value:Boolean):void
		{
			_touchable = value;
		}
		
		/**
		 * The view can be a class, a string to a file, or a display object. It must be supported by the view you target.
		 */
		public function get view():*
		{
			return _view;
		}
		
		[Inspectable(defaultValue="",format="File",type="String")]
		public function set view(value:*):void
		{
			_view = value;
		}
		
		/**
		 * @inheritDoc
		 */
		public function get art():ICitrusArt
		{
			return _art;
		}
		
		/**
		 * Used to invert the view on the y-axis, number of animations friendly!
		 */
		public function get inverted():Boolean
		{
			return _inverted;
		}
		
		public function set inverted(value:Boolean):void
		{
			_inverted = value;
		}
		
		public function get animation():String
		{
			return _animation;
		}
		
		public function set animation(value:String):void
		{
			_animation = value;
		}
		
		public function get offsetX():Number
		{
			return _offsetX;
		}
		
		[Inspectable(defaultValue="0")]
		public function set offsetX(value:Number):void
		{
			_offsetX = value;
		}
		
		public function get offsetY():Number
		{
			return _offsetY;
		}
		
		[Inspectable(defaultValue="0")]
		public function set offsetY(value:Number):void
		{
			_offsetY = value;
		}
		
		public function get registration():String
		{
			return _registration;
		}
		
		[Inspectable(defaultValue="topLeft",enumeration="center,topLeft")]
		public function set registration(value:String):void
		{
			_registration = value;
		}
		
		override public function update(timeDelta:Number):void
		{
			super.update(timeDelta);
			
			x += (_velocity.x * timeDelta);
			y += (_velocity.y * timeDelta);
		}

		public function get mouseChildren() : Boolean {
			return _mouseChildren;
		}
		
		public function set mouseChildren(value:Boolean):void {
			_mouseChildren = value;
		}
	}
}