package org.papervision3d.materials.special {
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.Graphics;
	import flash.geom.Matrix;
	import flash.geom.Rectangle;
	import flash.utils.getDefinitionByName;
	
	import org.papervision3d.core.geom.renderables.Particle;
	import org.papervision3d.core.log.PaperLogger;
	import org.papervision3d.core.render.data.RenderSessionData;
	import org.papervision3d.core.render.draw.IParticleDrawer;	
	
	/**
	 * A Particle material that is made from Class that extends a DisplayObject (ie a library symbol)
	 * 
	 * @author Seb Lee-Delisle
  	 */
  	 
	public class MovieAssetParticleMaterial extends ParticleMaterial implements IParticleDrawer
	{
		
		
		// TODO create object to store bitmap and spriterectdata (and USECOUNT!!!) for each type of bitmap
		public static var bitmapLibrary : Object = new Object(); 
		public static var spriteRectLibrary : Object = new Object();
		public static var useCount : Object = new Object();
		
		//private var _animated : Boolean; // animated movieclip - FOR FUTURE USE! NOT IMPLEMENTED YET :-) 
		
		private var scaleMatrix:Matrix;
		private var spriteRect:Rectangle;
		private var renderRect:Rectangle; 
		
		public var createUnique : Boolean = false; 
		
		/**
		* The MovieClip that is used as a texture.
		*/
		public var movie :DisplayObject;

		/**
		* A Boolean value that determines whether the MovieClip is transparent. The default value is true, which, 
		* although slower, is usually what you need for particles.
		*/
		public var movieTransparent :Boolean;
		
		private var movieAsset : Class;
		private var linkageID : String;

		//public var allowAutoResize:Boolean = true; // FOR FUTURE USE! 
		
		
		// __________________________________________________ NEW
		
		/**
		 * 
		 * @param linkageID		The Class or library symbol to make the material out of.
		 * @param transparent	[optional] - whether the image is transparent or not
		 * @param animated		[optional] NOT IMPLEMENTED YET! Please do not use! Coming soon though I PROMISE! :-) 
		 * @param createUnique	If true, we'll make a bitmap especially for use with this instance of the material, otherwise we'll use a cached version (if there is one)
		 * 
		 */

		public function MovieAssetParticleMaterial(linkageID:String, transparent:Boolean = true, animated : Boolean = false, createUnique:Boolean = false)
		{
			super(0,0);
			
			if(animated){
				PaperLogger.warning("WARNING animated MovieAssetParticleMaterial not yet implemented");
			}
			
			
			this.createUnique = createUnique;
			this.linkageID = linkageID; 
			movieTransparent = transparent; 
			
			
			if((bitmapLibrary[linkageID])&&(!createUnique))
			{
				bitmap = bitmapLibrary[linkageID];
				spriteRect = spriteRectLibrary[linkageID];
				useCount[linkageID]++; 	
			}
			else 
			{
				
				movieAsset  = Class(getDefinitionByName(linkageID)); 
				movie = DisplayObject(new movieAsset()); 
				
				spriteRect = movie.getBounds(movie); 
				bitmap = new BitmapData(movie.width, movie.height, movieTransparent, 0x00000000);
				
				if(!createUnique)
				{
					bitmapLibrary[linkageID] = bitmap;
					spriteRectLibrary[linkageID] = spriteRect; 
					useCount[linkageID] = 1; 
				} 
				
				
				
				var m:Matrix = new Matrix(); 
				m.tx = -spriteRect.left;
				m.ty = -spriteRect.top;
				bitmap.draw(movie, m); 
				
			}
			
		
			renderRect = new Rectangle() ;
			
			
			this.scaleMatrix = new Matrix();
		}
		
		/**
		 * Draws the particle as part of the render cycle. 
		 *  
		 * @param particle			The particle we're drawing
		 * @param graphics			The graphics object we're drawing into
		 * @param renderSessionData	The renderSessionData for this render cycle.
		 * 
		 */		
		override public function drawParticle(particle:Particle, graphics:Graphics, renderSessionData:RenderSessionData):void
		{
			var newscale : Number = particle.renderScale*particle.size; 
			
			scaleMatrix.identity();
			scaleMatrix.tx = spriteRect.left; 
			scaleMatrix.ty = spriteRect.top; 
			scaleMatrix.scale(newscale, newscale);
			scaleMatrix.translate(particle.vertex3D.vertex3DInstance.x, particle.vertex3D.vertex3DInstance.y); 
			
			var cullingrect:Rectangle = renderSessionData.viewPort.cullingRectangle;
			renderRect = cullingrect.intersection(particle.renderRect);
			graphics.beginBitmapFill(bitmap, scaleMatrix, false, smooth);
			graphics.drawRect(renderRect.x, renderRect.y, renderRect.width, renderRect.height);
			graphics.endFill();
			renderSessionData.renderStatistics.particles++;
			
			
		}
		
		/**
		 * This is called during the projection cycle. It updates the rectangular area that 
		 * the particle is drawn into. It's important for the culling phase. 
		 *  
		 * @param particle	The particle whose renderRect we're updating. 
		 * 
		 */		
		override public function updateRenderRect(particle : Particle) :void
		{
			
			var renderrect:Rectangle = particle.renderRect; 
			
			var newscale : Number = particle.renderScale*particle.size; 
			
			var osx:Number = newscale * spriteRect.left; 
			var osy:Number = newscale * spriteRect.top; 

			renderrect.x = particle.vertex3D.vertex3DInstance.x+osx;
			renderrect.y = particle.vertex3D.vertex3DInstance.y+osy;
			renderrect.width = particle.renderScale*particle.size*spriteRect.width;
			renderrect.height = particle.renderScale*particle.size*spriteRect.height;
			
			
		}
		
		/**
		 * Destroys the material.  
		 * 
		 */		
		override public function destroy() :void
		{
			super.destroy(); 
			// TODO Implement bitmap count for dictionary bitmaps and smart disposal
			if(createUnique) bitmap.dispose(); 
			else
			{
				useCount[linkageID]--; 
				if(useCount[linkageID]==0)
				{
					bitmapLibrary[linkageID].dispose(); 
					bitmapLibrary[linkageID] = null; 
					spriteRectLibrary[linkageID] = null; 
				
				}
				
				
			}
			
		}
	}
}
