package 
{
    import flash.ui.Keyboard;
    import away3dPlus.cameras.TargetedCamera;
    import mx.core.UIComponent;
    import mx.controls.Button;
    import caurina.transitions.Tweener;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.events.MouseEvent;
    import away3d.core.scene.View3D;
    import away3d.objects.Sphere;
    import away3d.core.material.WireColorMaterial;
    import away3d.core.math.Number3D;
    import away3d.core.scene.ObjectContainer3D;
    import away3dPlus.interfaces.ISpriteScene;
    import away3d.core.scene.Object3D;
    import away3d.objects.Triangle;
    import away3d.core.mesh.Segment;
    import away3dPlus.objects.WireCurve;
    import away3d.core.material.WireframeMaterial;
    import away3d.core.mesh.Vertex;
    import flash.geom.Rectangle;
    import away3d.core.draw.ScreenVertex;
    
    public class Away3DSprite extends Sprite implements ISpriteScene
    {
        public var view:View3D;
        //public var target:WireCurve;
           public var target:Object3D;
        private var rotatingX:int;
        private var rotatingY:int;
        private var camera:TargetedCamera;
        private var controls:UIComponent;

        private var viewing:int;
        private var cam3D:Boolean = false;
        private const TOP:int = 0;        
        private const SIDE:int = 1;        
        private const FRONT:int = 2;        
        
        public var container:ObjectContainer3D;
        public var top:Button;
        public var front:Button;
        public var side:Button;
        public var threeD:Button;
        public var zoomIn:Button;
        public var zoomOut:Button;
        
        public var zoomFactor:Number=2;
        //public var zero:Button;
        
        private var invalid:Boolean = true;
        public var tweening:int = 0;
        
        public function Away3DSprite(controls:UIComponent, container:ObjectContainer3D)
        {
            //trace("Hello World");
            this.controls = controls;
            this.container = container;
            
            target = new Object3D(); //Sphere({outline:new WireframeMaterial(0xFF7700), radius:100, segmentsW:4, segmentsH:1, y:0});
             target.visible = false;
            camera = new TargetedCamera(target);
            
            view = new View3D({camera:camera});
            addChild(view);

            view.scene.addChild(container);
            container.addChild(target);
            camera.z = -1000;

            configureStageListeners();
            
            configureControls();
            
            threeDView(null);
        }

        public function resize():void {
            if(stage != null) { // && view.x == 0 && view.y == 0) {
                view.x = parent.parent.width/2;
                view.y = parent.parent.height/2;
               }
        }

        public function invalidate():void {
            invalid = true;
        }
        
        /**
         * Sets up event listeners on the stage
         */
        private function configureStageListeners(): void
        {
            addEventListener(Event.ADDED_TO_STAGE, staged);
        }

        private function staged(event:Event):void {

            // Add arrow key handler, but we must be on stage first
            if(stage != null) {
                resize();
                addEventListener(Event.ENTER_FRAME, onEnterFrame);
                stage.addEventListener(KeyboardEvent.KEY_DOWN, handleKeyDown);
            }
        }

        /** 
         * Set up listeners for control panel events
         */
        private function configureControls():void {
            top = controls.getChildByName("top") as Button;
            top.addEventListener(MouseEvent.CLICK, topView);
            
            front = controls.getChildByName("front") as Button;
            front.addEventListener(MouseEvent.CLICK, frontView);
            
            side = controls.getChildByName("side") as Button;
            side.addEventListener(MouseEvent.CLICK, sideView);
            
            threeD = controls.getChildByName("threeD") as Button;
            threeD.addEventListener(MouseEvent.CLICK, threeDView);            

            zoomIn = controls.getChildByName("zoomIn") as Button;
            zoomIn.addEventListener(MouseEvent.CLICK, zoomInView);            

            zoomOut = controls.getChildByName("zoomOut") as Button;
            zoomOut.addEventListener(MouseEvent.CLICK, zoomOutView);            
        }

        public function topView(event:MouseEvent):void {
            if(viewing == TOP && !cam3D)
                return;
            startTween();
            Tweener.addTween(camera, {x:0, y:0, z:-1000*zoomFactor, time:1, transition:"easeOutCubic", onComplete:endTween});
            Tweener.addTween(container, {rotationX:90, rotationY:0, rotationZ:0, delay:0, time:1, transition:"easeOutCubic"});            
            viewing = TOP;
            cam3D = false;
        }

        public function frontView(event:MouseEvent):void {
            if(viewing == FRONT && !cam3D)
                return;
            startTween();
            Tweener.addTween(camera, {x:0, y:100*zoomFactor, z:-1000*zoomFactor, time:1, transition:"easeOutCubic", onComplete:endTween});
            Tweener.addTween(container, {rotationX:0, rotationY:0, rotationZ:0, delay:0, time:1, transition:"easeOutCubic"});            
            viewing = FRONT;
            cam3D = false;
        }

        public function sideView(event:MouseEvent):void {
            if(viewing == SIDE && !cam3D)
                return;
            startTween();
            Tweener.addTween(camera, {x:0, y:100*zoomFactor, z:-1000*zoomFactor, time:1, transition:"easeOutCubic", onComplete:endTween});
            Tweener.addTween(container, {rotationX:0, rotationY:90, rotationZ:0, delay:0, time:1, transition:"easeOutCubic"});            
            viewing = SIDE;
            cam3D = false
        }

        public function threeDView(event:MouseEvent):void {
            if(cam3D)
                return;
            startTween();
            Tweener.addTween(camera, {x:600*zoomFactor, y:600*zoomFactor, z:-600*zoomFactor, time:1, transition:"easeOutCubic", onComplete:endTween});            
            cam3D = true;
        }

        
        public function zoomInView(event:MouseEvent):void {
            startTween();
            var boom:Number = 3/4;
            Tweener.addTween(this, {zoomFactor:zoomFactor*boom, time:1, transition:"easeInOutCubic"});
            Tweener.addTween(camera,{x:camera.x*boom, y:camera.y*boom, z:camera.z*boom, time:1, transition:"easeInOutCubic", onComplete:endTween});
        }
        
        public function zoomOutView(event:MouseEvent):void {
            startTween();
            var boom:Number = 4/3;
            Tweener.addTween(this, {zoomFactor:zoomFactor*boom, time:1, transition:"easeInOutCubic"})
            Tweener.addTween(camera,{x:camera.x*boom, y:camera.y*boom, z:camera.z*boom, time:1, transition:"easeInOutCubic", onComplete:endTween});
        }

        public function resetView():void {
            zoomFactor=2;
            tweening = 0;
            cam3D = false;
            threeDView(null);
        }
        
        public function get extents():Rectangle {
            var minX:Number = Number.MAX_VALUE;
            var maxX:Number = Number.MIN_VALUE;
            var minY:Number = Number.MAX_VALUE;
            var maxY:Number = Number.MIN_VALUE;
            var xx:Number;
            var yy:Number;
            var zz:Number;
            for(var i:int = 0; i<2; i++) {
                xx = i==0? container.minX : container.maxX;
                for(var j:int = 0; j<2; j++) {
                    yy = j==0? container.minY : container.maxY;
                    for(var k:int = 0; k<2; k++) {
                        zz = k==0? container.minZ : container.maxZ;
                        var v:Vertex = new Vertex(xx, yy, zz);
                        var sv:ScreenVertex = camera.screen(container, v);
                        minX = Math.min(sv.x, minX);
                        minY = Math.min(sv.y, minY);
                        maxX = Math.max(sv.x, maxX);
                        maxY = Math.max(sv.y, maxY);
                        //trace("sv="+sv);
                    }
                }
            }
            return new Rectangle(minX, minY, maxX-minX, maxY-minY);
        }
        
        
        public function startTween():void {
            tweening++;
            //trace("++ ->" + tweening);
        }
        
        public function endTween():void {
            tweening--;
            trace("-- -> " + tweening);
            if(tweening <= 0) {
                tweening = 0;
                invalid = true;
            }
            
            /*
            //if(tweening == 0) {
                var rect:Rectangle = extents;
                trace("rect="+rect);
                var zin:Number = 0.8;
                var zout:Number = 3;
                if(isNaN(rect.width) || isNaN(rect.height) || rect.width > zout*parent.parent.width || rect.height > zout*parent.parent.height)
                    zoomOutView(null);
                else if(rect.width < zin*parent.parent.width || rect.height < zin*parent.parent.height)
                    zoomInView(null);
            //}
            */
            
        }
        
        private function handleKeyDown(event:KeyboardEvent):void {
            //trace(event.keyCode);
            if(event.keyCode == Keyboard.DOWN)
            {
                //frontView(null);
                if(container.rotationZ < 90)
                    container.rotationZ += 10;
                invalid = true;
            }
            else if(event.keyCode == Keyboard.UP)
            {
                //topView(null);
                if(container.rotationZ > -90)
                    container.rotationZ -= 10;
                invalid = true;
            }
            
            if(event.keyCode == Keyboard.LEFT)
            {
                //sideView(null);
                if(container.rotationX < 90)
                    container.rotationX += 10;
                invalid = true;
            }
            else if(event.keyCode == Keyboard.RIGHT)
            {
                //threeDView(null);
                if(container.rotationX > -90)
                container.rotationX -= 10;
                invalid = true;
            }        
        }
        
        protected function preRender():void {
            // This is a hook for derived classes needing to do pre-render updates.
            // e.g. adjusting any wireFrameMaterial lineWidths dependent on zoomFactor.
        }

        private function onEnterFrame(event:Event):void
        {
              if(invalid || tweening > 0) {
                  preRender();
                view.render();
                invalid = false;
            }
        }

    }

}