package {
	import flash.display.Sprite;
	import flash.events.*;
	import flash.utils.getTimer;
        import flash.utils.Timer;
        import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFieldType;
 
    // Cast3D dependencies
	import cast3d.core.Cast3d;
	import cast3d.core.events.LoadEvent;
	import cast3d.loader.Xc3Loader;
	import cast3d.utils.controls.*;
	import cast3d.utils.manipulators.Manipulator;
	import cast3d.utils.manipulators.sandy3d.TrackBall;
 
    // Sandy3D dependencies
	import sandy.core.Scene3D;
	import sandy.core.scenegraph.Camera3D;
	import sandy.core.scenegraph.Group;
	import sandy.core.light.Light3D;
 
	public class Sample extends Sprite
	{
		private var manipulator:TrackBall;
		private var animator:Cast3d;
		private var cp:ControlPanel;
 
		private var scene:Scene3D;
	        private var camera:Camera3D; 		
 
		private var loader:Xc3Loader; 
		private var loaded:Boolean; 
 
		private var statusText:TextField; 
		private var statusTimer:Timer;
 
		public function Sample()
		{
 			setup3DScene();
		}
 
		/**
		 * Configures the 3D scene
		 */		
		private function setup3DScene(): void
		{
			this.setupSandy();
			this.setupCast3D();
			this.setupControls();
			this.loadData();
 
			this.addEventListener(Event.ENTER_FRAME, this.handleEnterFrame);	
		}
 
  		/**
		 * initial setup for Sandy3D.
		 */		
		public function setupSandy(): void
		{		
		 // We create the camera
			 camera = new Camera3D( 600, 400 );
			 camera.near = 1;
 
			 // We create the "group" that is the tree of all the visible objects
	         var root:Group = new Group();
 
			 // We create a Scene and we add the camera and the objects tree 
		     scene = new Scene3D( "scene", this, camera, root );		     
		     scene.light = new Light3D(new Vector(0,0,1),100);
		}
 
  		/**
		 * initial setup for Cast3D.
		 */		
		public function setupCast3D(): void
		{		
                        this.loaded = false;
			this.animator = new Cast3d(this.scene, this.camera);
			this.animator.animationType = Cast3d.ANIMATION_TYPE_BYFRAME; //  ANIMATION_TYPE_REAL; //
			this.animator.fps = 22;
			this.animator.autoRewind = false;						
		}
 
  		/**
		 *  Function setups visual animation control panel.
		 */		
		public function setupControls(): void
		{		
			cp = new ControlPanel(animator);
			this.stage.addChild(cp);
//			cp.visible = false;	
 
			statusText = new TextField();
			statusText.textColor = 0x00ff00;
                        statusText.autoSize = TextFieldAutoSize.LEFT; 
                        statusText.type = TextFieldType.DYNAMIC;
                        statusText.y = cp.height;
                        this.stage.addChild(statusText);
		}
 
  		/**
		 *  Function performs 3D data  load from a X3c file.
		 */		
		private function loadData(): void
		{
			/** stealth - simple model, no animation */
			this.loader = new Xc3Loader("simple/stealth.x3c");
			this.loader.resourcePath = "simple/data";
 
			statusText.text = "loading file: " + loader.sourceURL; 
			statusTimer = new Timer(1000, 0.2);
			// designates listeners for the interval and completion events
			statusTimer.addEventListener(TimerEvent.TIMER, onTick);
			statusTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onTimerComplete);				 
			statusTimer.start();			
 
//			this.loader.preCalcMotion = true;
			this.loader.addEventListener(LoadEvent.LOAD_COMPLETE, this.cast3dLoadComplete);
			this.loader.addEventListener(LoadEvent.LOAD_ERROR, this.cast3dLoadError);						
			this.loader.load(this.animator.source);			
		}
 
  		/**
		 * Timer, updates current status 
		 */		
               private function onTick(event:TimerEvent):void 
               {
                    statusText.text = this.loader.loadstatus;        	        	            
               }
 
 		/**
		 * Timer handler
		 */		
               private function onTimerComplete(event:TimerEvent):void
               {
                        trace("Time's Up!");
			statusText.textColor = 0xff0000;
                         statusText.text = "Loading time exceeded 20 nimutes!"; 
                         removeTimer();       	        	            
                }
 
		/**
		 * At the end of load, removes timer
		 */		
                 private function removeTimer():void 
                {
           	   statusTimer.stop();
        	   statusTimer.removeEventListener(TimerEvent.TIMER,onTick);	   	                                                 statusTimer.removeEventListener(TimerEvent.TIMER_COMPLETE,onTimerComplete);
    	        }
 
		/**
		 * Handles the ENTER_FRAME event and updates the 3D scene.
		 */
		private function handleEnterFrame(event: Event): void
		{					
                        if (!this.loaded) return;
 
			var time:Number = getTimer();	
 
			// Update cast3D first		
			this.animator.render();
			// then render scene 	
			this.scene.render();
 
			// Update stat data		
			if (this.animator.source && cp)
			{
				var frame:int = this.animator.source.currentFrame; 
				var kframe:int = this.animator.source.currentKeyFrame; 
				cp.setCurrentFrame(kframe,frame);
				cp.setCurrentTime(animator.currentTime);
				cp.currentFps = 1000.0/(getTimer() - time);
			}
		}
 
		/**
		 * Handles mouse event
		 */		
	          public function mouseClicked(e:Event):void
	         {		        
			if (!this.animator.source) return;
 
			if (this.animator.isPlaying) 
			{
			  this.animator.pause();
			}
			else
			{
			  this.animator.play();
			}			
	         }
 
		/**
		 * Handles the load complete event
		 */		
		private function cast3dLoadComplete(event: LoadEvent): void
		{
			trace("cast3dLoadComplete ");
			this.manipulator = new TrackBall(this.animator,this.stage,
									 this.stage.stageWidth, this.stage.stageHeight,
									 Manipulator.Y_UP);
                           this.loaded = true;
                           removeTimer();       	        	            
                          if (loader.loaderror.length)
                          {
	 			statusText.textColor = 0xff0000;       	        	            
				statusText.text = loader.loaderror;            
                           }
                          else
                          {       	        	            
		   		statusText.visible = false;
                          }
		}
 
		/**
		 * Handles the load Error event
		 */		
		private function cast3dLoadError(event: LoadEvent): void
		{
			trace("cast3dLoadError ", event.message );
                        removeTimer();
   			statusText.textColor = 0xff0000;       	        	            
			statusText.text = event.message;
		}				
	}
    }