<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="718" height="848"
    creationComplete="initApp(event)" viewSourceURL="srcview/index.html">

    <mx:Style>
    
        Application 
        {
            /* make app window transparent */
            background-color:"";
            background-image:"";
            padding: 0px;
        }
        
        Button
        {
            paddingLeft: 0px;
            paddingRight: 0px;
        }
       
    </mx:Style>

    <mx:Script>
        <![CDATA[
            import mx.effects.Rotate;
            import mx.collections.ArrayCollection;
            import mx.core.UIComponent;
            import mx.controls.HTML;
            import flash.events.HTMLUncaughtScriptExceptionEvent;
            import flash.media.*;
            import com.everythingflex.air.managers.UpdateManager;
            
            private var html:HTML;
            
            private function initApp(event:Event):void {
                
                // Hide the top-level context menu items
                //Application.application.contextMenu.hideBuiltInItems();
                
                // Move the app when the lid image is dragged
                dryerLidImage.addEventListener( MouseEvent.MOUSE_DOWN, onLidMouseDown );

                // Wire up the drum timer for rotation animation
                drumTimer.addEventListener( TimerEvent.TIMER, onDrumTimerTick );
                
                // Add drop shadows for all the elements
                initShadows();
                
                // Create the HTML component
                var wrapper:UIComponent = new UIComponent();
                html = new HTML();
                
                // Match the size & location of the drum image
                // Add some fudge factors so that the worst case rotation (45 deg) doesn't cause the HTML control to "peek out" from behind
                html.x        = dryerDrumImage.x + 10;
                html.y        = dryerDrumImage.y - 10;
                html.width    = dryerDrumImage.width - 10;
                html.height    = dryerDrumImage.height - 10;
                wrapper.x = html.x;
                wrapper.y = html.y;
                wrapper.width = html.width;
                wrapper.height = html.height;
                html.x = 0;
                html.y = 0;
                
                // Wire up the HTML events we need to track
                html.addEventListener( Event.LOCATION_CHANGE, onHtmlLocationChange );
                html.addEventListener( Event.COMPLETE, onHtmlComplete );
                html.addEventListener( HTMLUncaughtScriptExceptionEvent.UNCAUGHT_SCRIPT_EXCEPTION, onUncaughtScriptException );
                
                // Now add the html control to the beginning of the display list
                wrapper.addChild( html );
                application.addChildAt( wrapper, 0 );

                // Wire up the rotation effect to the HTML component
                initRotation();
                
                // Check for app updates
                var um:UpdateManager = new UpdateManager("http://www.dryerfox.com/blog/DryerFox/version.xml");
                
                // Launch the browser on the home page
                onHomeClicked(event);
            }
            
            // Support for systemChrome="none" is lifted from the 'WeatherStation' sample app in the Apollo doc kit

            // Drop shadow support             
            private var shadowFilter:DropShadowFilter;
            
            private function initShadows():void {
                
                // creates a generic drop shadow to use on components that don't accept CSS shadow styles.
                // Example lifted from 'WeatherStation' Apollo sample app
                shadowFilter = new DropShadowFilter();
                shadowFilter.color = 0x000000;
                shadowFilter.alpha = 0.4;
                shadowFilter.blurX = 5;
                shadowFilter.blurY = 5;
                shadowFilter.distance = 5;
                
                // 'external' shadows
                addShadow(this.dryerLidImage);
                addShadow(this.dryerFrameImage);
                
                // 'internal' shadows
                addShadow(this.closeBtn);
                addShadow(this.minBtn);
                addShadow(this.startBtn);
                addShadow(this.stopBtn);
                addShadow(this.levelBtn);
                addShadow(this.backBtn);
                addShadow(this.fwdBtn);
                addShadow(this.homeBtn);
                addShadow(this.goBtn);
            }

            // Adds a standard drop shadow to a display object.
            public function addShadow(comp:DisplayObject):void {
                comp.filters = [this.shadowFilter];
            }

            // The following three methods handle the required custom chrome events
            
            private function onLidMouseDown(event:MouseEvent):void {
                // Move the app when the lid is clicked
                   stage.nativeWindow.startMove();
            }
            
            private function onMinClicked(event:MouseEvent):void {
                // Minimize the app
                stage.nativeWindow.minimize();
            }
            
            private function onCloseClicked(event:MouseEvent):void {
                // Just exit
                trace( "Buh-bye.");
                   stage.nativeWindow.close();
            }
            
            // Sound FX and animation support
            
            // Yup, that's really the sound of my dryer at home
            [Embed(source='/assets/DryerSound.mp3')]
            [Bindable]
            private var soundCls:Class;
            
            private var snd:Sound = new soundCls() as Sound;
            private var sndChannel:SoundChannel;
            
            // Actionscript doesn't have an enum type, so work around it with constants
            private static var kSoundIdle:int = 0; 
            private static var kSoundPlaying:int = 1; 
            private static var kSoundStopping:int = 2; 
            private var nSoundState:int = kSoundIdle;
            
            private var drumTimer:Timer = new Timer(0);
            
            private function onStartClicked(event:MouseEvent):void {
                startDrum();
            }
            
            private function onStopClicked(event:MouseEvent):void {
                stopDrum();
            }
            
            private function onSoundComplete(event:Event):void {
                onDrumStopped();
            }
            
            private function onLevelClicked(event:MouseEvent):void {
                levelDrum();
            }
            
            private function startDrum():void {
            
                switch( nSoundState )
                {
                    case kSoundIdle :
                    {
                        nSoundState = kSoundPlaying;
                        sndChannel = snd.play();
                        sndChannel.addEventListener(Event.SOUND_COMPLETE, onSoundComplete );
                        //trace( "Starting drum sound" );
                        
                        drumTimer.reset();
                        drumTimer.delay = 500;
                        drumTimer.repeatCount = 0; // Forever
                        drumTimer.start();
                        
                        if( rotateEffect.isPlaying )
                        {
                            rotateEffect.end();
                        }
                        rotateEffect.duration = drumTimer.delay * 2;
                        startRotate();

                        break;
                    }
                    
                    default :
                    {
                        //trace( "Start Nope: nSoundState=", nSoundState );
                        break;
                    }
                }
            }
            
            private function stopDrum():void {
                
                switch( nSoundState )
                {
                    case kSoundPlaying :
                    {
                        nSoundState = kSoundStopping;
                        //trace( "Sound shutting down" );
                        // Start the shutdown sound effect, which happens to be at 39 seconds into the drum sound effect.
                        var stopSoundChannel:SoundChannel = snd.play(39000);
                        stopSoundChannel.addEventListener(Event.SOUND_COMPLETE, onSoundComplete);
                        sndChannel.stop();
                        break;
                    }
                    
                    default :
                    {
                        //trace( "Stop Nope: nSoundState=", nSoundState );
                        break;
                    }
                }
            }
            
            private function onDrumStopped():void {
                
                switch( nSoundState )
                {
                    case kSoundPlaying :
                    case kSoundStopping :
                    {
                        if( nSoundState == kSoundPlaying )
                        {
                            //trace( "Sound completed on its own" );                        
                        }
                        else
                        {
                            //trace( "Quick stop complete" );                            
                        }
                        
                        nSoundState = kSoundIdle;
                        rotateEffect.end();
                        drumTimer.stop();
                        break;
                    }
                    
                    default :
                    {
                        //trace( "Complete Nope: nSoundState=", nSoundState );
                        break;
                    }
                }
            }
            
            private function levelDrum():void {
                
                if( nSoundState != kSoundIdle )
                {
                    // Stop any active sound
                    nSoundState = kSoundIdle;
                    sndChannel.stop();
                    drumTimer.stop();
                }
                
                // Quickly rotate back to a level state
                rotateEffect.end();
                rotateEffect.angleFrom = normalizeAngle( rotateEffect.angleTo );
                rotateEffect.angleTo = 0;
                rotateEffect.duration = 500;
                rotateEffect.play();
            }
                        
            // Apply the rotate effect to the HTML control
            private var rotateEffect:Rotate = new Rotate( html );
            
            private function initRotation():void {
                
                // Set the target
                var rotateTarget:UIComponent = html;
                rotateEffect.target = rotateTarget;
                
                // Rotate about the target's centre
                rotateEffect.originX = rotateTarget.width / 2;
                rotateEffect.originY = rotateTarget.height / 2;
            }

            private function onDrumTimerTick(event:TimerEvent):void {
                
                if( nSoundState == kSoundStopping )
                {
                    // Just ignore further animation modifications while shutting down
                    return;
                }
                
                if( rotateEffect.isPlaying )
                {
                    // Just update the target angle
                    rotateEffect.angleTo += 10;
                    rotateEffect.duration = drumTimer.delay * 2;
                    //trace( "Updating target angle to", rotateEffect.angleTo );
                }
                else
                {
                    // Restart the rotation
                    startRotate();
                }                
            }
            
            private function startRotate():void {
                
                // Restart the rotation                
                rotateEffect.angleFrom = normalizeAngle( rotateEffect.angleTo );
                rotateEffect.angleTo = rotateEffect.angleFrom + 45;
                rotateEffect.play();
                //trace( "Restarting rotation from", rotateEffect.angleFrom, "to", rotateEffect.angleTo );
            }
            
            private function normalizeAngle(angle:int):int {
                
                return( angle > 360 ? angle - 360 : angle );
            }
            
            // HTML navigation functions. Use the built-in history tracked by the WebKit control

            private function onUrlEnter( event:Event ):void {
                
                // Get the new URL
                var loc:String = urlTextInput.text;
                
                if( loc.indexOf( ":" ) < 0 )
                {
                    // Any default text assumes a HTTP request
                    loc = "http://" + url;
                }

                // Update the HTML location
                html.location = loc;
            }

            private function onBackClicked( event:Event ):void {
                html.historyBack();
            }
            
            private function onFwdClicked( event:Event ):void {
                html.historyForward();
            }
            
            private function onGoClicked( event:Event ):void {
                onUrlEnter(event);
            }
            
            private function onHomeClicked(event:Event):void {
                urlTextInput.text = "http://www.google.com";
                onUrlEnter(event);
            }
            
            private function onHtmlLocationChange(event:Event):void {
                
                var loc:String = html.location;
                urlTextInput.text = loc;
                
                // Start the drum when a new page begins loading
                startDrum();
            }
            
            private function onHtmlComplete(event:Event):void {
                
                // The page load is complete, so update the page title control
                pageTitleText.text = html.domWindow.window.document.title;
                
                // Enable the nav buttons as appropriate
                backBtn.enabled = ( html.historyPosition > 0 );
                fwdBtn.enabled  = ( html.historyPosition < html.historyLength - 1 ); 

                // Stop the drum, or more accurately, begin the animation shutdown sequence, so we hear the dryer stop
                stopDrum();                
            }
            
            private function onUncaughtScriptException(event:HTMLUncaughtScriptExceptionEvent):void {
                // Just log any javascript exceptions and keep going
                trace( "Ignoring", event.exceptionValue, "stackTrace=", event.stackTrace );
            }
            
        ]]>
    </mx:Script>

    <mx:Image  x="2"   y="0"   width="715" height="215" id="dryerLidImage"   source="@Embed('/assets/dryer_lid_med.png')"   scaleContent="false" autoLoad="true" toolTip="Drag here to move the dryer"/>
    <mx:Image  x="-1"  y="198" width="719" height="650" id="dryerFrameImage" source="@Embed('/assets/dryer_frame_med.png')" scaleContent="false" autoLoad="true" mouseEnabled="false" mouseFocusEnabled="false"/>
    <mx:Image  x="102" y="270" width="495" height="495" id="dryerDrumImage"  source="@Embed('/assets/dryer_drum_med.png')"  scaleContent="false" autoLoad="true" mouseEnabled="false" mouseFocusEnabled="false" alpha="0.3"/>
                   
    <mx:Button x="115" y="28"  width="22" label="x"    id="closeBtn" click="onCloseClicked(event)" toolTip="Close DryerFox"/>
    <mx:Button x="105" y="73"  width="22" label="+"    id="startBtn" click="onStartClicked(event)" toolTip="Start spinning the drum"/>
    <mx:Button x="130" y="73"  width="22" label="-"    id="stopBtn"  click="onStopClicked(event)"  toolTip="Stop spinning the drum"/>
    <mx:Button x="588" y="67"  width="22" label="_"    id="levelBtn" click="onLevelClicked(event)" toolTip="Level the drum"/>
    <mx:Button x="588" y="29"  width="22" label="v"    id="minBtn"   click="onMinClicked(event)"   toolTip="Minimize DryerFox"/>
    <mx:Button x="16"  y="179" width="22" label="&lt;" id="backBtn"  click="onBackClicked(event)"  toolTip="Back"/>
    <mx:Button x="41"  y="179" width="22" label="&gt;" id="fwdBtn"   click="onFwdClicked(event)"   toolTip="Forward"/>
    <mx:Button x="65"  y="179" width="22" label="h"    id="homeBtn"  click="onHomeClicked(event)"  toolTip="Home"/>
    <mx:Button x="678" y="179" width="22" label="!"    id="goBtn"    click="onGoClicked(event)"    toolTip="Go"/>
    
    <mx:TextInput x="89" y="179" width="587" id="urlTextInput"  borderStyle="none" backgroundAlpha="0.0" enter="onUrlEnter(event)" toolTip="Enter a URL here"/>
    <mx:Text      x="92" y="99"  width="539" id="pageTitleText" text="Hello" textAlign="center"/>
    
</mx:Application>