package exampleSupport {
	import com.transmote.flar.FLARMarker;
	import com.transmote.utils.geom.FLARPVGeomUtils;
	
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.utils.Dictionary;
	
	import org.libspark.flartoolkit.core.param.FLARParam;
	import org.libspark.flartoolkit.pv3d.FLARCamera3D;
	import org.papervision3d.lights.PointLight3D;
	import org.papervision3d.materials.shadematerials.FlatShadeMaterial;
	import org.papervision3d.materials.utils.MaterialsList;
	import org.papervision3d.objects.DisplayObject3D;
	import org.papervision3d.objects.primitives.Cube;
	import org.papervision3d.render.LazyRenderEngine;
	import org.papervision3d.scenes.Scene3D;
	import org.papervision3d.view.Viewport3D;
	
	
	/**
	 * standard FLARToolkit Papervision3D example, with our friends the Cubes.
	 * code is borrowed heavily from Saqoosha, Mikko Haapoja, and Squidder.
	 * http://saqoosha.net/en/flartoolkit/start-up-guide/
	 * http://www.mikkoh.com/blog/?p=182
	 * http://www.squidder.com/2009/03/06/flar-how-to-multiple-instances-of-multiple-markers/#more-285
	 * 
	 * @author	Eric Socolofsky
	 * @url		http://transmote.com/flar
	 */
	public class SimpleCubes extends Sprite {
		private static const CUBE_SIZE:Number = 40;
		
		private var viewport3D:Viewport3D;
		private var camera3D:FLARCamera3D;
		private var scene3D:Scene3D;
		private var renderEngine:LazyRenderEngine;
		private var pointLight3D:PointLight3D;
		
		private var markersByPatternId:Vector.<Vector.<FLARMarker>>;	// FLARMarkers, arranged by patternId
		private var containersByMarker:Dictionary;						// Cube containers, hashed by corresponding FLARMarker
		
		
		public function SimpleCubes (numPatterns:uint, cameraParams:FLARParam, viewportWidth:Number, viewportHeight:Number) {
			this.init(numPatterns);
			this.initPapervisionEnvironment(cameraParams, viewportWidth, viewportHeight);
		}

		public function addMarker (marker:FLARMarker) :void {
			// store marker
			var markerList:Vector.<FLARMarker> = this.markersByPatternId[marker.patternId];
			markerList.push(marker);
			
			// create a new Cube, and place it inside a container (DisplayObject3D) for manipulation
			var container:DisplayObject3D = new DisplayObject3D();
			var materialsList:MaterialsList = new MaterialsList({all: this.getMaterialByPatternId(marker.patternId)});
			var cube:Cube = new Cube(materialsList, CUBE_SIZE, CUBE_SIZE, CUBE_SIZE);
			cube.z = 20;
			container.addChild(cube);
			this.scene3D.addChild(container);
			
			// associate container with corresponding marker
			this.containersByMarker[marker] = container;
		}
		
		public function removeMarker (marker:FLARMarker) :void {
			// find and remove marker
			var markerList:Vector.<FLARMarker> = this.markersByPatternId[marker.patternId];
			var markerIndex:uint = markerList.indexOf(marker);
			if (markerIndex != -1) {
				markerList.splice(markerIndex, 1);
			}
			
			// find and remove corresponding container
			var container:DisplayObject3D = this.containersByMarker[marker];
			if (container) {
				this.scene3D.removeChild(container);
			}
			delete this.containersByMarker[marker]
		}
		
		private function init (numPatterns:uint) :void {
			// set up lists (Vectors) of FLARMarkers, arranged by patternId
			this.markersByPatternId = new Vector.<Vector.<FLARMarker>>(numPatterns, true);
			while (numPatterns--) {
				this.markersByPatternId[numPatterns] = new Vector.<FLARMarker>();
			}
			
			// prepare hashtable for associating Cube containers with FLARMarkers
			this.containersByMarker = new Dictionary(true);
		}
		
		private function initPapervisionEnvironment (cameraParams:FLARParam, viewportWidth:Number, viewportHeight:Number) :void {
			this.scene3D = new Scene3D();
			this.camera3D = new FLARCamera3D(cameraParams);
			
			this.viewport3D = new Viewport3D(viewportWidth, viewportHeight);
			this.addChild(this.viewport3D);
			
			this.renderEngine = new LazyRenderEngine(this.scene3D, this.camera3D, this.viewport3D);
			
			this.pointLight3D = new PointLight3D();
			this.pointLight3D.x = 1000;
			this.pointLight3D.y = 1000;
			this.pointLight3D.z = -1000;
			
			this.addEventListener(Event.ENTER_FRAME, this.onEnterFrame);
		}
		
		private function onEnterFrame (evt:Event) :void {
			this.updateCubes();
			this.renderEngine.render();
		}
		
		private function updateCubes () :void {
			// update all Cube containers according to the transformation matrix in their associated FLARMarkers
			var i:int = this.markersByPatternId.length;
			var markerList:Vector.<FLARMarker>;
			var marker:FLARMarker;
			var container:DisplayObject3D;
			var j:int;
			while (i--) {
				markerList = this.markersByPatternId[i];
				j = markerList.length;
				while (j--) {
					marker = markerList[j];
					container = this.containersByMarker[marker];
					container.transform = FLARPVGeomUtils.translateFLARMatrixToPVMatrix(marker.transformMatrix);
				}
			}
		}
		
		private function getMaterialByPatternId (patternId:int) :FlatShadeMaterial {
			var colorId:int = patternId % 5;
			switch (colorId) {
				case 0:
					return new FlatShadeMaterial(this.pointLight3D, 0x47b200, 0x1B4200);
				case 1:
					return new FlatShadeMaterial(this.pointLight3D, 0x990000, 0x420000);
				case 2:
					return new FlatShadeMaterial(this.pointLight3D, 0xFF7F00, 0x472400);
				case 3:
					return new FlatShadeMaterial(this.pointLight3D, 0xFFCC33, 0x47390E);
				case 4:
				default:
					return new FlatShadeMaterial(this.pointLight3D, 0xF2F2B2, 0x4A4A37);
			}
		}
	}
}