package mx.core
{
   import flash.geom.Point;
   import flash.display.DisplayObjectContainer;
   import flash.events.Event;
   import flash.system.ApplicationDomain;
   import flash.display.BitmapData;
   
   public class BitmapAsset extends FlexBitmap implements IFlexAsset, IFlexDisplayObject, ILayoutDirectionElement
   {
      
      public function BitmapAsset(bitmapData:BitmapData = null, pixelSnapping:String = "auto", smoothing:Boolean = false)
      {
         var appDomain:ApplicationDomain = null;
         super(bitmapData,pixelSnapping,smoothing);
         if(FlexVersionClass == null)
         {
            appDomain = ApplicationDomain.currentDomain;
            if(appDomain.hasDefinition("mx.core::FlexVersion"))
            {
               FlexVersionClass = Class(appDomain.getDefinition("mx.core::FlexVersion"));
            }
         }
         if((FlexVersionClass) && (FlexVersionClass["compatibilityVersion"] >= FlexVersionClass["VERSION_4_0"]))
         {
            this.addEventListener(Event.ADDED,this.addedHandler);
         }
      }
      
      mx_internal  static const VERSION:String = "4.5.1.21328";
      
      private static var FlexVersionClass:Class;
      
      private static var MatrixUtilClass:Class;
      
      private var layoutFeaturesClass:Class;
      
      private var layoutFeatures:IAssetLayoutFeatures;
      
      override public function get x() : Number
      {
         return this.layoutFeatures == null?super.x:this.layoutFeatures.layoutX;
      }
      
      override public function set x(value:Number) : void
      {
         if(this.x == value)
         {
            return;
         }
         if(this.layoutFeatures == null)
         {
            super.x = value;
         }
         else
         {
            this.layoutFeatures.layoutX = value;
            this.validateTransformMatrix();
         }
      }
      
      override public function get y() : Number
      {
         return this.layoutFeatures == null?super.y:this.layoutFeatures.layoutY;
      }
      
      override public function set y(value:Number) : void
      {
         if(this.y == value)
         {
            return;
         }
         if(this.layoutFeatures == null)
         {
            super.y = value;
         }
         else
         {
            this.layoutFeatures.layoutY = value;
            this.validateTransformMatrix();
         }
      }
      
      override public function get z() : Number
      {
         return this.layoutFeatures == null?super.z:this.layoutFeatures.layoutZ;
      }
      
      override public function set z(value:Number) : void
      {
         if(this.z == value)
         {
            return;
         }
         if(this.layoutFeatures == null)
         {
            super.z = value;
         }
         else
         {
            this.layoutFeatures.layoutZ = value;
            this.validateTransformMatrix();
         }
      }
      
      override public function get width() : Number
      {
         var p:Point = null;
         if(this.layoutFeatures == null)
         {
            return super.width;
         }
         if(MatrixUtilClass != null)
         {
            p = MatrixUtilClass["transformSize"](this.layoutFeatures.layoutWidth,this._height,transform.matrix);
         }
         return p?p.x:super.width;
      }
      
      override public function set width(value:Number) : void
      {
         if(this.width == value)
         {
            return;
         }
         if(this.layoutFeatures == null)
         {
            super.width = value;
         }
         else
         {
            this.layoutFeatures.layoutWidth = value;
            this.layoutFeatures.layoutScaleX = !(this.measuredWidth == 0)?value / this.measuredWidth:0;
            this.validateTransformMatrix();
         }
      }
      
      private var _height:Number;
      
      override public function get height() : Number
      {
         var p:Point = null;
         if(this.layoutFeatures == null)
         {
            return super.height;
         }
         if(MatrixUtilClass != null)
         {
            p = MatrixUtilClass["transformSize"](this.layoutFeatures.layoutWidth,this._height,transform.matrix);
         }
         return p?p.y:super.height;
      }
      
      override public function set height(value:Number) : void
      {
         if(this.height == value)
         {
            return;
         }
         if(this.layoutFeatures == null)
         {
            super.height = value;
         }
         else
         {
            this._height = value;
            this.layoutFeatures.layoutScaleY = !(this.measuredHeight == 0)?value / this.measuredHeight:0;
            this.validateTransformMatrix();
         }
      }
      
      override public function get rotationX() : Number
      {
         return this.layoutFeatures == null?super.rotationX:this.layoutFeatures.layoutRotationX;
      }
      
      override public function set rotationX(value:Number) : void
      {
         if(this.rotationX == value)
         {
            return;
         }
         if(this.layoutFeatures == null)
         {
            super.rotationX = value;
         }
         else
         {
            this.layoutFeatures.layoutRotationX = value;
            this.validateTransformMatrix();
         }
      }
      
      override public function get rotationY() : Number
      {
         return this.layoutFeatures == null?super.rotationY:this.layoutFeatures.layoutRotationY;
      }
      
      override public function set rotationY(value:Number) : void
      {
         if(this.rotationY == value)
         {
            return;
         }
         if(this.layoutFeatures == null)
         {
            super.rotationY = value;
         }
         else
         {
            this.layoutFeatures.layoutRotationY = value;
            this.validateTransformMatrix();
         }
      }
      
      override public function get rotationZ() : Number
      {
         return this.layoutFeatures == null?super.rotationZ:this.layoutFeatures.layoutRotationZ;
      }
      
      override public function set rotationZ(value:Number) : void
      {
         if(this.rotationZ == value)
         {
            return;
         }
         if(this.layoutFeatures == null)
         {
            super.rotationZ = value;
         }
         else
         {
            this.layoutFeatures.layoutRotationZ = value;
            this.validateTransformMatrix();
         }
      }
      
      override public function get rotation() : Number
      {
         return this.layoutFeatures == null?super.rotation:this.layoutFeatures.layoutRotationZ;
      }
      
      override public function set rotation(value:Number) : void
      {
         if(this.rotation == value)
         {
            return;
         }
         if(this.layoutFeatures == null)
         {
            super.rotation = value;
         }
         else
         {
            this.layoutFeatures.layoutRotationZ = value;
            this.validateTransformMatrix();
         }
      }
      
      override public function get scaleX() : Number
      {
         return this.layoutFeatures == null?super.scaleX:this.layoutFeatures.layoutScaleX;
      }
      
      override public function set scaleX(value:Number) : void
      {
         if(this.scaleX == value)
         {
            return;
         }
         if(this.layoutFeatures == null)
         {
            super.scaleX = value;
         }
         else
         {
            this.layoutFeatures.layoutScaleX = value;
            this.layoutFeatures.layoutWidth = Math.abs(value) * this.measuredWidth;
            this.validateTransformMatrix();
         }
      }
      
      override public function get scaleY() : Number
      {
         return this.layoutFeatures == null?super.scaleY:this.layoutFeatures.layoutScaleY;
      }
      
      override public function set scaleY(value:Number) : void
      {
         if(this.scaleY == value)
         {
            return;
         }
         if(this.layoutFeatures == null)
         {
            super.scaleY = value;
         }
         else
         {
            this.layoutFeatures.layoutScaleY = value;
            this._height = Math.abs(value) * this.measuredHeight;
            this.validateTransformMatrix();
         }
      }
      
      override public function get scaleZ() : Number
      {
         return this.layoutFeatures == null?super.scaleZ:this.layoutFeatures.layoutScaleZ;
      }
      
      override public function set scaleZ(value:Number) : void
      {
         if(this.scaleZ == value)
         {
            return;
         }
         if(this.layoutFeatures == null)
         {
            super.scaleZ = value;
         }
         else
         {
            this.layoutFeatures.layoutScaleZ = value;
            this.validateTransformMatrix();
         }
      }
      
      private var _layoutDirection:String = "ltr";
      
      public function get layoutDirection() : String
      {
         return this._layoutDirection;
      }
      
      public function set layoutDirection(value:String) : void
      {
         if(value == this._layoutDirection)
         {
            return;
         }
         this._layoutDirection = value;
         this.invalidateLayoutDirection();
      }
      
      public function get measuredHeight() : Number
      {
         if(bitmapData)
         {
            return bitmapData.height;
         }
         return 0;
      }
      
      public function get measuredWidth() : Number
      {
         if(bitmapData)
         {
            return bitmapData.width;
         }
         return 0;
      }
      
      public function invalidateLayoutDirection() : void
      {
         var mirror:* = false;
         var p:DisplayObjectContainer = parent;
         while(p)
         {
            if(p is ILayoutDirectionElement)
            {
               mirror = (!(this._layoutDirection == null)) && (!(ILayoutDirectionElement(p).layoutDirection == null)) && (!(this._layoutDirection == ILayoutDirectionElement(p).layoutDirection));
               if((mirror) && (this.layoutFeatures == null))
               {
                  this.initAdvancedLayoutFeatures();
                  if(this.layoutFeatures != null)
                  {
                     this.layoutFeatures.mirror = mirror;
                     this.validateTransformMatrix();
                  }
               }
               else if((!mirror) && (this.layoutFeatures))
               {
                  this.layoutFeatures.mirror = mirror;
                  this.validateTransformMatrix();
                  this.layoutFeatures = null;
               }
               
               break;
            }
            p = p.parent;
         }
      }
      
      public function move(x:Number, y:Number) : void
      {
         this.x = x;
         this.y = y;
      }
      
      public function setActualSize(newWidth:Number, newHeight:Number) : void
      {
         this.width = newWidth;
         this.height = newHeight;
      }
      
      private function addedHandler(event:Event) : void
      {
         this.invalidateLayoutDirection();
      }
      
      private function initAdvancedLayoutFeatures() : void
      {
         var appDomain:ApplicationDomain = null;
         var features:IAssetLayoutFeatures = null;
         if(this.layoutFeaturesClass == null)
         {
            appDomain = ApplicationDomain.currentDomain;
            if(appDomain.hasDefinition("mx.core::AdvancedLayoutFeatures"))
            {
               this.layoutFeaturesClass = Class(appDomain.getDefinition("mx.core::AdvancedLayoutFeatures"));
            }
            if(MatrixUtilClass == null)
            {
               if(appDomain.hasDefinition("mx.utils::MatrixUtil"))
               {
                  MatrixUtilClass = Class(appDomain.getDefinition("mx.utils::MatrixUtil"));
               }
            }
         }
         if(this.layoutFeaturesClass != null)
         {
            features = new this.layoutFeaturesClass();
            features.layoutScaleX = this.scaleX;
            features.layoutScaleY = this.scaleY;
            features.layoutScaleZ = this.scaleZ;
            features.layoutRotationX = this.rotationX;
            features.layoutRotationY = this.rotationY;
            features.layoutRotationZ = this.rotation;
            features.layoutX = this.x;
            features.layoutY = this.y;
            features.layoutZ = this.z;
            features.layoutWidth = this.width;
            this._height = this.height;
            this.layoutFeatures = features;
         }
      }
      
      private function validateTransformMatrix() : void
      {
         if(this.layoutFeatures != null)
         {
            if(this.layoutFeatures.is3D)
            {
               super.transform.matrix3D = this.layoutFeatures.computedMatrix3D;
            }
            else
            {
               super.transform.matrix = this.layoutFeatures.computedMatrix;
            }
         }
      }
   }
}
