package com.partlyhuman.apollo.windowing
{
    import flash.display.NativeWindow;
    import flash.events.EventDispatcher;
    import flash.utils.getQualifiedClassName;
    
    import mx.core.UIComponent;
    import flash.events.Event;
    import flash.system.Shell;

    /**
     * @author Roger Braunstein | partlyhuman.com
     */
    [Event(type="com.partlyhuman.apollo.windowing.WindowManagerEvent", name="windowsUpdated")]
    public class WindowManager extends EventDispatcher
    {
        protected var factory:WindowManagerSimple;
        protected var appWindows:Array;
        protected var docWindows:Array;
        
        protected static var instance:WindowManager;
        
        public function WindowManager(key:SingletonEnforcer)
        {
            super();
            if (key == null) throw new ArgumentError();
            factory = WindowManagerSimple.getInstance();
            appWindows = new Array();
            docWindows = new Array();
            
            factory.mainWindow.addEventListener(Event.CLOSING, onMainWindowClosing);
        }
        
        public static function getInstance():WindowManager
        {
            if (!instance) instance = new WindowManager(new SingletonEnforcer());
            return instance;
        }
        
        public function newApplicationWindow(name:String, viewClass:Class, options:Object = null, width:int = 0, height:int = 0):WindowHandle
        {
            var view:UIComponent = UIComponent(new viewClass());
            var window:NativeWindow = factory.newWindow(view, name, options, width, height);
            var handle:WindowHandle = new WindowHandle(WindowType.APPLICATION_WINDOW, window, view, name);
            handle.addEventListener(Event.CLOSE, onWindowClose);
            appWindows.push(handle);
            dispatchEvent(new WindowManagerEvent(WindowManagerEvent.WINDOWS_UPDATED));
            return handle;
        }
                
        public function newDocumentWindow(viewClass:Class, friendlyDocumentClassName:String = "Document", options:Object = null, width:int = 0, height:int = 0):WindowHandle
        {
            var view:UIComponent = UIComponent(new viewClass());
            var title:String = friendlyDocumentClassName + " " + (docWindows.length + 1);
            var window:NativeWindow = factory.newWindow(view, title, options, width, height);
            var handle:WindowHandle = new WindowHandle(WindowType.DOCUMENT_WINDOW, window, view);
            handle.addEventListener(Event.CLOSE, onWindowClose);
            docWindows.push(handle);
            dispatchEvent(new WindowManagerEvent(WindowManagerEvent.WINDOWS_UPDATED));
            return handle;
        }
        
        
        public function getAllWindows():Array
        {
            return appWindows.concat(docWindows);
        }
        
        public function getHandle(window:NativeWindow):WindowHandle
        {
            var windows:Array = getAllWindows();
            var ret:Array = windows.filter(function(item:*, index:int, array:Array):Boolean
            {
                return (WindowHandle(item).window == window);
            });
            return (ret.length > 0)? WindowHandle(ret[0]) : null;
        }
        
        public function getApplicationWindowByName(name:String):WindowHandle
        {
            var ret:Array = appWindows.filter(function(item:*, index:int, array:Array):Boolean
            {
                return (WindowHandle(item).name == name);
            });
            return (ret.length > 0)? WindowHandle(ret[0]) : null;
        }
        
        public function getApplicationWindows():Array
        {
            return appWindows.concat();
        }
        
        public function getDocumentWindows():Array
        {
            return docWindows.concat();
        }
        
        public function getTopWindow():WindowHandle
        {
            return getHandle(Shell.shell.activeWindow);
        }
        
        protected function onWindowClose(event:Event):void
        {
            var handle:WindowHandle = WindowHandle(event.target);
            var arr:Array = (handle.type == WindowType.DOCUMENT_WINDOW)? docWindows : appWindows;
            arr.splice(arr.indexOf(handle), 1);
            dispatchEvent(new WindowManagerEvent(WindowManagerEvent.WINDOWS_UPDATED));
        }
        
        protected function onMainWindowClosing(event:Event):void
        {
            var windows:Array = getAllWindows();
            for each (var handle:WindowHandle in windows)
            {
                handle.window.close();
            }
        }
    }
}
class SingletonEnforcer{}