package com.justinimhoff.techlabs {
    import mx.containers.Canvas;
    import flash.events.MouseEvent;
    import flash.desktop.NativeApplication;
    import mx.containers.HBox;
    import mx.controls.Button;
    import mx.styles.StyleManager;
    import flash.display.NativeWindowDisplayState;
    import mx.events.FlexEvent;
    import flash.display.NativeWindow;
    import mx.containers.VBox;
    import mx.core.WindowedApplication;
    import mx.controls.Image;

    /**
     *
     *  Creates a native application window based on the Canvas components which impliments an abolute layout.
     *  The appWindow leverages a MAC and PC skin based on either user preferance or operating system.
     *  Allows for essentially 4 states: active - inactive, mac-pc
     *
     */
    public class AppWindow extends Canvas {
        // create componets that can be referanced when data is changed
        private var windowControls:HBox;
        private var header:HBox;
        private var closeButton:Button;
        private var minimizeButton:Button;
        private var maximizeButton:Button;
        private var resizeButton:Button;
        private var winCloseGlow:Image;
        private var winMinimizeGlow:Image;
        private var winMaximizeGlow:Image
        //create view managers
        private var _active:Boolean=true;
        private var _os:String;
        /*----------------------------------------------
           Embed pc control Glow for use in pc theme on rollOver
           A better solution would be to load the images in the pc swf, but currently Flex CSS can only be used for styles, not properties.
           the source of an image is a property, not a style
         ---------------------------------------------*/
        [Embed(source="images/pc_close_GLOW.png")]
        private var win_close_GLOW:Class;

        [Embed(source="images/pc_maximize_GLOW.png")]
        private var win_maximize_GLOW:Class;

        [Embed(source="images/pc_minimize_GLOW.png")]
        private var win_minimize_GLOW:Class;

        // Constructor
        //  Set default properties
        public function AppWindow() {
            super();
            percentWidth=100;
            percentHeight=100;
            addEventListener(FlexEvent.CREATION_COMPLETE, layoutWindow);
        }

        /*----------------------------------------------
           Use the creation complete event to style and layout children of the AppWindow
           If you override the createChildren function, you cannot add componets to the AppWindow in mxml
         ---------------------------------------------*/
        private function layoutWindow(event:FlexEvent):void {
            //You must set the style property of the container after it has been created
            styleName="active";
            //Create a horizontal box to store the close,  minimize, and maximize controls 
            windowControls=new HBox();
            windowControls.addEventListener(MouseEvent.ROLL_OVER, windowControlRollOver);
            windowControls.addEventListener(MouseEvent.ROLL_OUT, windowControlRollOut);
            /*/----------------------------------------------
               Create the Glow and set visible to false - the glow should only be visible on the pc theme on rollOver
             ---------------------------------------------/*/
            winCloseGlow=new Image();
            winCloseGlow.visible=false;
            winCloseGlow.source=win_close_GLOW;
            //---------------------//
            winMaximizeGlow=new Image();
            winMaximizeGlow.visible=false;
            winMaximizeGlow.source=win_maximize_GLOW;
            //---------------------//
            winMinimizeGlow=new Image();
            winMinimizeGlow.visible=false;
            winMinimizeGlow.source=win_minimize_GLOW;
            /*/----------------------------------------------
               Create control buttons to manage the active window
               Set each button to a default style name that is inherits style from the last style loaded
               Identify each button for use in referance when an event is dispatched
               Create event listners
             ---------------------------------------------/*/
            closeButton=new Button();
            closeButton.styleName="close";
            closeButton.id="close";
            closeButton.addEventListener(MouseEvent.CLICK, closeWindow);
            closeButton.addEventListener(MouseEvent.ROLL_OVER, controlRollOver);
            closeButton.addEventListener(MouseEvent.ROLL_OUT, controlRollOut);
            //---------------------//
            minimizeButton=new Button();
            minimizeButton.styleName="minimize";
            minimizeButton.id="minimize";
            minimizeButton.addEventListener(MouseEvent.CLICK, minimizeWindow);
            minimizeButton.addEventListener(MouseEvent.ROLL_OVER, controlRollOver);
            minimizeButton.addEventListener(MouseEvent.ROLL_OUT, controlRollOut);
            //---------------------//
            maximizeButton=new Button();
            maximizeButton.styleName="maximize";
            maximizeButton.id="maximize";
            maximizeButton.addEventListener(MouseEvent.CLICK, maximizeWindow);
            maximizeButton.addEventListener(MouseEvent.ROLL_OVER, controlRollOver);
            maximizeButton.addEventListener(MouseEvent.ROLL_OUT, controlRollOut);
            //Create  a resize button and set an event listner to deal with dragging of the active window
            resizeButton=new Button();
            resizeButton.styleName="resizeButton";
            resizeButton.addEventListener(MouseEvent.MOUSE_DOWN, resizeWindow);
            //Create a header that is used for activeWindow movement - move the window
            header=new HBox();
            header.height=53;
            header.addEventListener(MouseEvent.MOUSE_DOWN, moveWindow);
            //Add control button sto the control horizontal box
            windowControls.addChild(closeButton);
            windowControls.addChild(minimizeButton);
            windowControls.addChild(maximizeButton);
            //Add all components  to the parent in order of view - window controls are layed out on top of the Glow
            addChildAt(header, 1);
            addChild(winCloseGlow);
            addChild(winMinimizeGlow);
            addChild(winMaximizeGlow);
            addChild(windowControls);
            addChild(resizeButton);
        }

        /*----------------------------------------------
           Create a getter and setter that manages the active view of the application - if the application has focus , set style and allow visible interaction
           Allows the parent to set the view from active to inactive.
         ---------------------------------------------*/
        public function get active():Boolean {
            return _active;
        }

        public function set active(value:Boolean):void {
            _active=value;
            if (_active) {
                closeButton.enabled=true;
                minimizeButton.enabled=true;
                maximizeButton.enabled=true;
                styleName="active";
            } else {
                closeButton.enabled=false;
                minimizeButton.enabled=false;
                maximizeButton.enabled=false;
                styleName="inactive";
            }
            invalidateDisplayList();
        }

        /*----------------------------------------------
           Create getter and setter for applications OS or for user interactions, to change the view of the application
           This also re-arranges the children in the control holder depending on OS.
         ---------------------------------------------*/
        public function get os():String {
            return _os;
        }

        public function set os(value:String):void {
            _os=value;
            if (_os == "MAC") {
                setMacWindow();
                windowControls.setChildIndex(closeButton, 0);
                windowControls.setChildIndex(minimizeButton, 1);
                windowControls.setChildIndex(maximizeButton, 2);
            } else {
                setWinWindow();
                windowControls.setChildIndex(minimizeButton, 0);
                windowControls.setChildIndex(maximizeButton, 1);
                windowControls.setChildIndex(closeButton, 2);
            }
            //We have successfully created the window, re-arranged the control and added listners, now we want to mark it to be redawn when possible
            //We dont want to update the component  as each child is added, but instead make one call that the component is ready to be re-measured and layed out
            invalidateDisplayList();
        }

        /*-------------------------------------------------------------------------
           View manager
           This programatically sets a runtime style of the application window

         *** NOTE ****
           When programtically managing a view, manage only the properties and set the style name;

           GOOD
           windowControls.styleName= "componentViewName";

         **StyleSheet
           .componentViewName{
           top:24;
           }

           BAD
           windowControls.setStyle("top", 24);

           WHY?
           if using a setStyle, you are overriding the global style and  incurr a heavy perfomance hit - only use when dynamically setting style on exisiting objects
           You want to use the styleName when setting up an object for the first time.
           This call is extremely resource intensive, due to the fact that when set it then  requires all children to do a style lookup
         --------------------------------------------------------------------------*/
        private function setWinWindow():void {
            resizeButton.styleName="resizeButton";
            header.styleName="header";
            windowControls.styleName="winWindowControl";
            winCloseGlow.styleName="glowClose";
            winMinimizeGlow.styleName="glowMinimize";
            winMaximizeGlow.styleName="glowMaximize";
        }

        private function setMacWindow():void {
            resizeButton.styleName="resizeButton";
            header.styleName="header";
            windowControls.styleName="macWindowControl";
        }

        /*-------------------------------------------------------------------------
           AppWindow specific event handlers.
         --------------------------------------------------------------------------*/
        private function moveWindow(event:MouseEvent):void {
            NativeApplication.nativeApplication.activeWindow.startMove();
        }

        private function closeWindow(event:MouseEvent):void {
            NativeApplication.nativeApplication.activeWindow.close()
        }

        private function minimizeWindow(event:MouseEvent):void {
            NativeApplication.nativeApplication.activeWindow.minimize()
        }

        private function resizeWindow(event:MouseEvent):void {
            NativeApplication.nativeApplication.activeWindow.startResize()
        }

        //handles the toggle of the application fullscreen view
        private function maximizeWindow(event:MouseEvent):void {
            if (NativeApplication.nativeApplication.activeWindow.displayState == NativeWindowDisplayState.MAXIMIZED) {
                NativeApplication.nativeApplication.activeWindow.restore();
            } else {
                NativeApplication.nativeApplication.activeWindow.maximize();
            }
            if (_os == "MAC") {
                setMacWindow();
            } else {
                setWinWindow();
            }
        }

        //When rolling over the window control - for the MAC we want to chang the state for all button to over which we do by selecting each.
        private function windowControlRollOver(event:MouseEvent):void {
            //We want to stop the event from bubbling back up - we know this is where we want to capture the event and no where else should it be referanced
            event.stopImmediatePropagation();
            if (_os == "MAC") {
                minimizeButton.selected=true;
                maximizeButton.selected=true;
                closeButton.selected=true;
            }
        }

        //Deselect all buttons on the MAC, if you didnot check for MAC, you would be setting values that you dont need. 
        private function windowControlRollOut(event:MouseEvent):void {
            event.stopImmediatePropagation();
            if (_os == "MAC") {
                minimizeButton.selected=false;
                maximizeButton.selected=false;
                closeButton.selected=false;
            }
        }

        // If the action if on a PC and the window is active - make the Glow visible on the resource the event originated from - the target
        private function controlRollOver(event:MouseEvent):void {
            event.stopImmediatePropagation();
            if (_os == "WIN") {
                if (_active) {
                    if (event.currentTarget.id == "close") {
                        winCloseGlow.visible=true;
                    } else if (event.currentTarget.id == "maximize") {
                        winMaximizeGlow.visible=true;
                    } else {
                        winMinimizeGlow.visible=true;
                    }
                }
            }
        }

        //If Mac - return, if the application does not have focus - return, else hide Glow for the targeted component
        private function controlRollOut(event:MouseEvent):void {
            event.stopImmediatePropagation();
            if (_os == "MAC")
                return;
            if (!_active)
                return;
            if (event.currentTarget.id == "close") {
                winCloseGlow.visible=false;
            } else if (event.currentTarget.id == "maximize") {
                winMaximizeGlow.visible=false;
            } else {
                winMinimizeGlow.visible=false;
            }
        }

    }
}