package {
    import away3d.core.material.MovieMaterial;
    import away3d.core.material.TransformBitmapMaterial;
    import away3d.core.math.Number3D;
    import away3d.core.render.BasicRenderer;
    import away3d.core.render.Renderer;
    import away3d.core.scene.Camera3D;
    import away3d.core.scene.ObjectContainer3D;
    import away3d.core.scene.Scene3D;
    import away3d.core.scene.View3D;
    import away3d.core.utils.Cast;
    import away3d.objects.Cube;
    import away3d.objects.Plane;
    
    import caurina.transitions.Tweener;
    
    import com.adobe.viewsource.ViewSource;
    
    import flash.display.Loader;
    import flash.display.MovieClip;
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageDisplayState;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.filters.ColorMatrixFilter;
    import flash.filters.GlowFilter;
    import flash.ui.Keyboard;
    import flash.utils.clearTimeout;
    import flash.utils.getTimer;
    import flash.utils.setTimeout;
    
    [SWF(backgroundColor="#000000", frameRate="30", quality="LOW", width="800", height="600")]
    public class LFPUG_the_third_way extends Sprite
    {
        [Embed(source="images/A Terror of Orchids.jpg")]
        public static var Orchids:Class;
        
        [Embed(source="images/signature.swf")]
        public static var SignatureSwf:Class;
        
        [Embed(source="images/slides.swf", mimeType="application/octet-stream")]
        public static var Slides:Class;
        
        protected var camera:Camera3D;
        protected var backView:View3D;
        protected var foreView:View3D;
        protected var floor:Plane;
        protected var ceiling:Plane;
        
        protected var prevCarousel:ObjectContainer3D;
        protected var prevSlideMaterial:MovieMaterial;
        protected var prevSlideFilter:ColorMatrixFilter;
        protected var prevSlide:Cube;
        
        protected var nextCarousel:ObjectContainer3D;
        protected var nextSlideMaterial:MovieMaterial;
        protected var nextSlideFilter:ColorMatrixFilter;
        protected var nextSlide:Cube;
        
        protected var orchidMaterial:TransformBitmapMaterial;
        protected var ceilingMaterial:TransformBitmapMaterial;
        
        protected var background:Scene3D;
        protected var foreground:Scene3D;
        
        protected var Signature:MovieClip;
        protected var mist:Sprite;
        protected var slidesArray:Array = new Array();
        protected var slidesLoader:Loader = new Loader();
        private var active:Boolean = false;
        private var animation:Boolean = true;
        private var time:int;
        
        private var currentSlideIndex:int = 0;
        
        public function LFPUG_the_third_way()
        {
            super();
            
            //take care of stage
            //stage.quality = StageQuality.LOW;
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;
            //stage.showDefaultContextMenu = false;
            stage.stageFocusRect = false;
            ViewSource.addMenuItem(this, "srcview/index.html")
            
            
            //get slides
            slidesLoader.contentLoaderInfo.addEventListener(Event.INIT, onSlidesReady);
            slidesLoader.loadBytes(new Slides());
            
            
            
        }
                
        private function onSlidesReady(event:Event):void
        {
            var index:Number = 1;
            var symbol:Class;
            var symbolInstance:MovieClip;
            try {
                while (symbol = (slidesLoader.contentLoaderInfo.applicationDomain.getDefinition("Slide" + String(index++)) as Class))
                {
                    symbolInstance = new symbol() as MovieClip;
                    symbolInstance.stop();
                    slidesArray.push(symbolInstance);
                }
            } catch (error:Error) {
                setupScene();
            }
        }
        
        public function setupScene():void
        {
            //setup camera
            camera = new Camera3D({zoom:3, focus:200, z:-1000});
            
            //setup background
            orchidMaterial = new TransformBitmapMaterial(Cast.bitmap(Orchids), {scaleX:0.1, scaleY:0.1, repeat:true, precision:2.5});
            floor = new Plane({material:orchidMaterial, width:3000, height:5000, z:500, y:200, rotationY:90, bothsides:true});
            ceiling = new Plane({material:orchidMaterial, width:3000, height:5000, z:500, y:-200, rotationY:90, bothsides:true});
            background = new Scene3D(floor, ceiling);
            
            //create background view and add to displaylist
            backView = new View3D({camera:camera, scene:background, renderer:Renderer.BASIC});
            addChild(backView);
            
            //create mist and add it to displaylist
            mist = new Sprite();
            mist.filters = [new GlowFilter(0xEC00B8, 1, 200, 200, 2, 1)];
            addChild(mist);
            
            //add signature
            Signature = MovieClip(new SignatureSwf());
            addChild(Signature);
            
            //setup foreground
            prevSlideMaterial = new MovieMaterial(slidesArray[0], {throughProjection:true, projectionVector:new Number3D(0, 0, 1), offsetX:-400, offsetY:-300, precision:2.5});
            prevSlideFilter = new ColorMatrixFilter();
            prevSlide = new Cube({ownCanvas:true, filters:[prevSlideFilter], material:prevSlideMaterial, z:-9575, width:800, height:600, depth:50});
            prevCarousel = new ObjectContainer3D({z:9000}, prevSlide);
            
            nextSlideMaterial = new MovieMaterial(slidesArray[1], {throughProjection:true, projectionVector:new Number3D(0, 0, 1), offsetX:-400, offsetY:-300, precision:2.5});
            nextSlideFilter = new ColorMatrixFilter();
            nextSlide = new Cube({ownCanvas:true, filters:[nextSlideFilter], material:nextSlideMaterial, width:800, height:600, depth:50});
            nextCarousel = new ObjectContainer3D({z:9000}, nextSlide);
            
            foreground = new Scene3D(prevCarousel, nextCarousel);
            
            //create foreground view and add to displaylist
            foreView = new View3D({camera:camera, scene:foreground, renderer:new BasicRenderer()});
            addChild(foreView);
            
            stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
            stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
            stage.addEventListener(Event.RESIZE, onResize);
            onResize(null);
            foreView.render();
        }
        
        private function onKeyDown(event:KeyboardEvent):void
        {
            if (active)
                return;
            
            switch (event.keyCode)
            {
                case Keyboard.ENTER:
                    if (stage.displayState == StageDisplayState.FULL_SCREEN)
                        stage.displayState =StageDisplayState.NORMAL;
                    else 
                        stage.displayState =StageDisplayState.FULL_SCREEN;
                    break;
                case Keyboard.LEFT:
                    onPrevSlide();
                    break;
                case Keyboard.RIGHT:
                    onNextSlide();
                    break;
                case Keyboard.DOWN:
                    (slidesArray[currentSlideIndex] as MovieClip).nextFrame();
                    foreView.render();
                    break;
                case Keyboard.UP:
                    (slidesArray[currentSlideIndex] as MovieClip).prevFrame();
                    foreView.render();
                    break;
                default:
            }
        }
        
        public function clearAll():void
        {
            //clear any unfinished timeouts
            if (nextTimeout)
                clearTimeout(nextTimeout);
            if (prevTimeout)
                clearTimeout(prevTimeout);
            
            //clear any unfinished tweens
            Tweener.removeAllTweens();
            
        }
        
        internal var nextTimeout:int;
        
        public function onNextSlide():void
        {
            if (currentSlideIndex >= slidesArray.length - 1)
                return;
            
            clearAll();
            currentSlideIndex++;
            active = true;
            
            //setup prev slide
            prevSlideMaterial.movie = slidesArray[currentSlideIndex-1]
            prevSlide.z = -9575;
            prevSlide.rotationX = 0;
            prevSlide.rotationY = 0;
            prevCarousel.rotationY = 0;
            
            //setup next slide
            nextSlideMaterial.movie = slidesArray[currentSlideIndex]
            nextSlide.z = -2000;
            nextSlide.rotationX = 0;
            nextSlide.rotationY = 0;
            nextCarousel.rotationY = -45;
            
            //trigger animation
            onNextSlideOut();
        }
        
        public function onNextSlideOut():void
        {
            //start tweens
            Tweener.addTween(prevCarousel, {rotationY:45, time:1.5, transition:"easeinquad"});
            Tweener.addTween(prevSlide, {z:-2000, rotationX:360, rotationY:360, time:1.5, transition:"easeinquad"});
            nextTimeout = setTimeout(onNextSlideIn, 1000);
        }
        
        public function onNextSlideIn():void
        {
            nextCarousel.visible = true;
            //start tweens
            Tweener.addTween(nextCarousel, {rotationY:0, time:1.5, transition:"easeoutquad"});
            Tweener.addTween(nextSlide, {z:-9575, rotationX:360, rotationY:360, time:1.5, transition:"easeoutquad", onComplete:setTimeout, onCompleteParams:[disableRender, 200]});
        }
        
        internal var prevTimeout:int;
        
        public function onPrevSlide():void
        {
            if (currentSlideIndex <= 0)
                return;
            
            clearAll();
            currentSlideIndex--;
            active = true;
            
            //setup prev slide
            prevSlideMaterial.movie = slidesArray[currentSlideIndex]
            prevSlide.z = -2000;
            prevSlide.rotationX = 0;
            prevSlide.rotationY = 0;
            prevCarousel.rotationY = 45;
            
            //setup next slide
            nextSlideMaterial.movie = slidesArray[currentSlideIndex+1]
            nextSlide.z = -9575;
            nextSlide.rotationX = 0;
            nextSlide.rotationY = 0;
            nextCarousel.rotationY = 0;
            
            //trigger animation
            onPrevSlideOut();
        }
        
        public function onPrevSlideOut():void
        {
            //start tweens
            Tweener.addTween(nextCarousel, {rotationY:-45, time:1.5, transition:"easeinquad"});
            Tweener.addTween(nextSlide, {z:-2000, rotationX:360, rotationY:360, time:1.5, transition:"easeinquad"});
            prevTimeout = setTimeout(onPrevSlideIn, 1000);
        }
        
        public function onPrevSlideIn():void
        {
            nextCarousel.visible = true;
            //start tweens
            Tweener.addTween(prevCarousel, {rotationY:0, time:1.5, transition:"easeoutquad"});
            Tweener.addTween(prevSlide, {z:-9575, rotationX:360, rotationY:360, time:1.5, transition:"easeoutquad", onComplete:setTimeout, onCompleteParams:[disableRender, 200]});
        }
        
        public function disableRender():void
        {
            active = false;
        }
        
        internal var tintR:int = 236;
        internal var tintG:int = 0;
        internal var tintB:int = 184;
        
        public function onEnterFrame(event:Event):void
        {
            
            if (animation)
                time = getTimer();
            
            if (!active)
                return;
            
            //update star gate
            if (orchidMaterial.offsetX > 256)
                orchidMaterial.offsetX -= 248;
            else
                orchidMaterial.offsetX += 8;
            
            //update prev tint
            var prevFraction:Number = (-2000 - prevSlide.z)/7575;
            prevSlideFilter.matrix = [prevFraction, 0, 0, 0, tintR*(1-prevFraction),
                                        0, prevFraction, 0, 0, tintG*(1-prevFraction),
                                        0, 0, prevFraction, 0, tintB*(1-prevFraction),
                                        0, 0, 0, 1, 0]
                                        
            //update next tint
            var nextFraction:Number = (-2000 - nextSlide.z)/7575;
            nextSlideFilter.matrix = [nextFraction, 0, 0, 0, tintR*(1-nextFraction),
                                        0, nextFraction, 0, 0, tintG*(1-nextFraction),
                                        0, 0, nextFraction, 0, tintB*(1-nextFraction),
                                        0, 0, 0, 1, 0]
                                        
            background.updateTime(time);
            backView.render();
            foreground.updateTime(time);
            foreView.render();
        }
        
                
        private function onResize(event:Event):void 
        {
            foreView.x = backView.x = stage.stageWidth / 2;
            foreView.y = backView.y = stage.stageHeight / 2;
            foreView.scaleX = stage.stageWidth/800;
            foreView.scaleY = stage.stageHeight/600;
            Signature.y = stage.stageHeight - Signature.height;
            
            //redraw mist
            mist.graphics.clear();
            mist.graphics.beginFill(0xEC00B8);
            mist.graphics.moveTo(-200, stage.stageHeight / 2 - 50);
            mist.graphics.lineTo(stage.stageWidth + 200, stage.stageHeight / 2 - 50);
            mist.graphics.lineTo(stage.stageWidth + 200, stage.stageHeight / 2 + 50);
            mist.graphics.lineTo(-200, stage.stageHeight / 2 + 50);
            mist.graphics.endFill();
        }
    }
}