package classes.away3d.graphs.bsp
{
	import classes.away3d.core.base.*;
	import classes.away3d.graphs.bsp.*;
	import classes.away3d.materials.*;
	import classes.away3d.tools.utils.*;
	
	import flash.display.*;
	import flash.geom.*;
	
	/**
	 * Ray to BSP geometry hittest
	 * Ideal to build FPS game, where weapons need to check a hit, in order to animate a missile etc...
	 */
 
	public final class BSPHitTest
	{
		private var _tree:BSPTree;
		private var _lastHitname:String;
		private var _intersect:Vector3D = new Vector3D(0.0,0.0,0.0);
		private var _result:Vector3D = new Vector3D(0.0,0.0,0.0);
		private var _EPSintersect:Vector3D = new Vector3D(0.0,0.0,0.0);
		 
		/**
		 * Creates a new BSPHittest object.
		 *
		 * @param a BSPTree instance
		 */
		public function BSPHitTest(bspTree:BSPTree)
		{
			_tree = bspTree;
		}
		
		/**
		* Finds the closest intersection along a segment with the BSP planes 
		* 
		* @param start	The starting position (camera position for instance)
		* @param end	The position (the camera position for instance)
		*
		* @return A Vector3D of the intersection. Null if no hit.
		*/
		public function getIntersectPosition(start:Vector3D, end:Vector3D):Vector3D
		{
			if(_tree.traceCollision(start, end)){
				
				var collisionRatio:Number = _tree.collisionRatio;
				_intersect.x = start.x + collisionRatio*(end.x-start.x);
				_intersect.y = start.y + collisionRatio*(end.y-start.y);
				_intersect.z = start.z + collisionRatio*(end.z-start.z);
				
				return _intersect;
			}
			
			return null;
		}
		
		/**
		* Finds the uv's and the map of the face found at the closest intersection, the closest intersection along a segment with the BSP planes 
		* 
		* @param start	The starting position (camera position for instance)
		* @param end	The position (the camera position for instance)
		
		* @return An Array or null
				
				array = [intersection, uv, bitmapdata]
				[Vector3D, the intersection in space, 
				UV of the intersection. Null if no hit or nodeleaf is empty,
				the bitmapData assigned to the face. Null if there's not]
			
		*/
		public function getUVIntersectPosition(start:Vector3D, end:Vector3D):Array
		{
			_result = getIntersectPosition(start, end);
			
			if(_result == null)
				return null;
			
			_EPSintersect.x = _result.x + _tree.collisionPlane.a * BSPTree.EPSILON;
			_EPSintersect.y = _result.y + _tree.collisionPlane.b * BSPTree.EPSILON;
			_EPSintersect.z = _result.z + _tree.collisionPlane.c * BSPTree.EPSILON;
			 
			var node:BSPNode = _tree.getLeafContaining(_EPSintersect);
			
			if(node == null)
				return null;
			
			var faces:Vector.<Face> = node.mesh.geometry.faces;
			
			//empty node
			if(faces.length == 0)
				return null;
			
			var f:Face;
			var uv:UV;
			
			for(var i:int = 0;i<faces.length;++i){
				f = faces[i];
				uv = BaryCentricTest.getUVs(f.v0, f.v1, f.v2, f.uv0, f.uv1, f.uv2, _result);
				if(uv != null){
					_lastHitname = node.name;
					var bmd:BitmapData = (f.material is BitmapMaterial)? BitmapMaterial(f.material).bitmap : null;
					return [_result, uv, bmd];
				}				
			}

			return null; 
		}
		
		/**
		* if a dynamic mesh was added to tree with a name, on hit test you might want retrieve its name
		* and compare with your saved names list.
		* Works only after getUVIntersectPosition method has been used.
		*/
		public function get lastHittedMeshName():String
		{
			return _lastHitname;
		}

	}
}