<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" width="848" height="660" showTitleBar="true" showGripper="true" title="MM Ticker Browser"
    closing="handleClosing(event)" creationComplete="init()" minHeight="500" minWidth="750" 
    xmlns:ns1="flex.utils.ui.resize.*" xmlns:local="*" styleName="windowStyle"
    paddingBottom="0" paddingLeft="0" paddingRight="0" paddingTop="0" horizontalAlign="left" verticalGap="0" showStatusBar="false" titleIcon="@Embed(source='img/appIcon.png')" viewSourceURL="srcview/index.html">

    <mx:Style source="main.css"/>
    
    <mx:Script>
        <![CDATA[
            import mx.core.Application;
            import Dialog.DialogNote;
            import flash.utils.setInterval;
            import mx.managers.PopUpManager;
            import Dialog.DialogSendIssue;
            import Dialog.DialogAbout;
            import flash.utils.setTimeout;
            import mx.binding.utils.BindingUtils;
            import mx.events.MenuEvent;
            import mx.containers.TitleWindow;
            import mx.events.ScrollEvent;
            import mx.events.FlexEvent;
            import mx.containers.Canvas;
            import flex.utils.ui.resize.ResizableWindow;
            import flex.utils.ui.resize.ResizablePanel;
            import mx.controls.HTML;
            import mx.containers.VBox;
            import mx.controls.List;
            import mx.events.CloseEvent;
            import mx.controls.Alert;
            import mx.collections.ArrayCollection;
            import flash.filesystem.*;

            public var prefsFile:File; // The preferences prefsFile
            private var loaded:Boolean = false;
            [Bindable] public var prefsXML:XML; // The XML data
            public var stream:FileStream; // The FileStream object used to read and write prefsFile data.
            [Bindable]
            private var listTickers:ArrayCollection = new ArrayCollection();
            [Bindable]
            private var listURLs:ArrayCollection = new ArrayCollection();
            [Bindable]
            private var listLocalURLs:ArrayCollection = new ArrayCollection();
            
            private var oldNotesWindow:DialogNote;
            
             private function init():void
             {
                 prefsFile = File.applicationStorageDirectory;
                prefsFile = prefsFile.resolvePath("preferences.xml"); 
                // add right click to basic windows so we can reset position if needed
                for each(var o:Object in (tabMain.getChildAt(0) as Canvas).getChildren())
                {
                    if(o is ResizableWindow)
                    {
                        var moveToZero:ContextMenuItem = new ContextMenuItem("Reset Position");
                        moveToZero.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, handleMoveToZero);
                        (o as ResizableWindow).contextMenu = new ContextMenu();
                        (o as ResizableWindow).contextMenu.addItem(moveToZero);
                    }
                }
                loadPreferences();
                loaded = true;
                
                var cm:ContextMenu = new ContextMenu();
                var noteItem:ContextMenuItem = new ContextMenuItem("Add Note Window");
                noteItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, handleAddNote);
                cm.addItem(noteItem);
                    
                tabMain.contextMenu = cm;
                
                setInterval(savePreferences, 15000);
             }
            
            private function handleAddURL(e:KeyboardEvent):void
            {
                if(e.keyCode == 13)
                {
                    var url:String = txtTickerURL.text;
                    AddURL(url);
                }
            }
            
            private function AddURL(url:String):void
            {
                if(url == null || url == "")
                    return;
                if(url.indexOf("{ticker}") == -1)
                {
                    Alert.show("Please make sure \"{ticker}\" is included in the URL!");
                    return;
                }
                if(!listURLs.contains(url))
                {
                    listURLs.addItem(url);
                    txtTickerURL.text = "";
                    for (var i:int = 1; i < tabMain.getChildren().length ; ++i)
                    {
                        // add another window to each tab
                        var c:Canvas = tabMain.getChildAt(i) as Canvas;
                        AddTickerWindow(c, c.label.toUpperCase(), url);
                    }
                }
            }
            
            private function handleAddLocalURL(e:KeyboardEvent):void
            {
                if(e.keyCode == 13)
                {
                    var url:String = txtLocalURL.text;
                    AddLocalURL(url);
                }
            }
            
            private function AddLocalURL(url:String):void
            {
                if(url == null || url == "")
                    return;
                if(!listURLs.contains(url))
                {
                    listLocalURLs.addItem(url);
                    txtLocalURL.text = "";
                    AddLocalWindow(url);
                }
            }
            
            private function handleAddTicker(e:KeyboardEvent):void
            {
                if(e.keyCode == 13)
                {
                    var ticker:String = txtTicker.text;
                    AddTicker(ticker);
                }
            }
            
            private function handleHtmlComplete(e:Event):void
            {
                return;
                var html:CustomHTML = e.currentTarget as CustomHTML;
                var url:String = html.tag.url.toString();
                if(html.parent.parent == tabMain.selectedChild && tabMain.selectedIndex != 0)
                //html.setVScrollPos(parseInt(prefsXML.html.(@href == url)[0].@verticalScroll));
                    html.setHScrollPos(parseInt(prefsXML.html.(@href == url)[0].@horizontalScroll));
            }
            
            private function AddTickerWindow(c:Canvas, ticker:String, url:String):void
            {
                var p:ResizableWindow = new ResizableWindow();
                p.title = url;
                p.movable = true;
                //p.addEventListener(Event.RESIZE, handleWindowUpdate);
                p.addEventListener("dragEnd", handleWindowUpdate); // essentially a move, right?
                p.addEventListener(MouseEvent.MOUSE_UP, handleWindowUpdate);
                p.addEventListener("lockChanged", handleWindowLockChanged);
                p.addEventListener("scaleYChanged", handleWindowScaleUpdate);
                p.addEventListener("scaleXChanged", handleWindowScaleUpdate);
                
                var html:CustomHTML = new CustomHTML();
                html.addEventListener(Event.COMPLETE, handleHtmlComplete);
                if(prefsXML.html.(@href == url).length() > 0)
                {
                    p.x = prefsXML.html.(@href == url)[0].@x;
                    p.y = prefsXML.html.(@href == url)[0].@y;
                    p.width = prefsXML.html.(@href == url)[0].@width;
                    p.height = prefsXML.html.(@href == url)[0].@height;
                    var scaleX:Number = parseFloat(prefsXML.html.(@href == url)[0].@scaleX);
                    var scaleY:Number = parseFloat(prefsXML.html.(@href == url)[0].@scaleY);
                    if(scaleX > 0)
                        p.scaleX = scaleX;
                    if(scaleY > 0)
                        p.scaleY = scaleY; 
                    p.locked = prefsXML.html.(@href == url)[0].@locked.toString() == "true";
                    html.setVScrollPos(parseInt(prefsXML.html.(@href == url)[0].@verticalScroll));
                    html.setHScrollPos(parseInt(prefsXML.html.(@href == url)[0].@horizontalScroll));
                    
                }
                else
                {
                    p.width = 400;
                    p.height = 400;
                }
                
                html.tag.url = url;
                html.setLocation(url.replace(new RegExp(/{ticker}/g), ticker.toUpperCase()));
                p.addChild(html);
                p.contextMenu = createContextMenu();
                html.percentHeight = 100;
                html.percentWidth = 100;
                c.addChild(p);
            }
            
            // add a window with this URL to the first page
            private function AddLocalWindow(url:String):void
            {
                var p:ResizableWindow = new ResizableWindow();
                p.title = url;
                p.movable = true;
                //p.addEventListener(Event.RESIZE, handleWindowUpdate);
                p.addEventListener("dragEnd", handleWindowUpdate); // essentially a move, right?
                p.addEventListener(MouseEvent.MOUSE_UP, handleWindowUpdate);
                p.addEventListener("lockChanged", handleWindowLockChanged);
                p.addEventListener("scaleYChanged", handleWindowScaleUpdate);
                p.addEventListener("scaleXChanged", handleWindowScaleUpdate);
                
                var html:CustomHTML = new CustomHTML();
                //BindingUtils.bindProperty(html, "verticalScrollPolicy", p, "verticalScrollPolicy");
                //BindingUtils.bindProperty(html, "horizontalScrollPolicy", p, "horizontalScrollPolicy");
                html.addEventListener(Event.COMPLETE, handleHtmlComplete);
                if(prefsXML.html.(@href == url).length() > 0)
                {
                    p.x = prefsXML.html.(@href == url)[0].@x;
                    p.y = prefsXML.html.(@href == url)[0].@y;
                    p.width = prefsXML.html.(@href == url)[0].@width;
                    p.height = prefsXML.html.(@href == url)[0].@height;
                    var scaleX:Number = parseFloat(prefsXML.html.(@href == url)[0].@scaleX);
                    var scaleY:Number = parseFloat(prefsXML.html.(@href == url)[0].@scaleY);
                    if(scaleX > 0)
                        p.scaleX = scaleX;
                    if(scaleY > 0)
                        p.scaleY = scaleY; 
                    p.locked = prefsXML.html.(@href == url)[0].@locked.toString() == "true";
                    html.setVScrollPos(parseInt(prefsXML.html.(@href == url)[0].@verticalScroll));
                    html.setHScrollPos(parseInt(prefsXML.html.(@href == url)[0].@horizontalScroll));
                }
                else
                {
                    p.x = pnlLocal.x + pnlLocal.width + 60;
                    p.y = pnlLocal.y + 30;
                    p.width = 400;
                    p.height = 400;
                }
                
                html.tag.url = url;
                html.location = url;
                p.addChild(html);
                p.contextMenu = createContextMenu();
                html.percentHeight = 100;
                html.percentWidth = 100;
                (tabMain.getChildAt(0) as Canvas).addChild(p);
            }
            
            private function createContextMenu():ContextMenu
            {
                var cm:ContextMenu = new ContextMenu();
                
                var refreshItem:ContextMenuItem = new ContextMenuItem("Refresh");
                refreshItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, handleRefreshSelect);
                cm.addItem(refreshItem);
                
                var moveToZero:ContextMenuItem = new ContextMenuItem("Reset Position");
                moveToZero.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, handleMoveToZero);
                cm.addItem(moveToZero);
                
                var scaleSubMenu:ContextMenuItem = new ContextMenuItem("Scale");
                scaleSubMenu.submenu = new NativeMenu();
                for(var i:int = 5; i <= 100; i += 5)
                {
                    var scaleItem:ContextMenuItem = new ContextMenuItem(i.toString() + "%");
                    scaleItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, handleScaleSelect);
                    scaleSubMenu.submenu.addItem(scaleItem);
                }                
                cm.addItem(scaleSubMenu);
                
                var open:ContextMenuItem = new ContextMenuItem("Open in Browser");
                open.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, handleOpenURL);
                cm.addItem(open);
                
                cm.addEventListener(ContextMenuEvent.MENU_SELECT, handleDisplayMenu);
                
                return cm;
            }
            
            private function handleWindowLockChanged(e:Event):void
            {
                var win:ResizableWindow = e.currentTarget as ResizableWindow;
                if(win == null)
                    return;
                var html:CustomHTML = (win.getChildAt(0) as CustomHTML);
                
                // save prefs for this window
                var url:String;
                if(html == null)
                    url = win.title;
                else
                    url = html.tag.url.toString();
                if(url != null)
                {
                    if(prefsXML.html.(@href == url).length() == 0)
                    {
                        prefsXML.appendChild(new XML("<html href=\"" + url + "\"/>"));
                    }
                        
                    prefsXML.html.(@href == url)[0].@locked = win.locked.toString();
                }
                
                // lock other windows with this URL
                if(win.parent != tabMain.getChildAt(0))
                {
                    for each(var c:Canvas in tabMain.getChildren())
                    {
                        if(c == tabMain.getChildAt(0))
                            continue;
                        for each(var w:ResizableWindow in c.getChildren())
                        {
                            if(win != w && (win.getChildAt(0) as CustomHTML) && (w.getChildAt(0) as CustomHTML).tag.url.toString() == url)
                            {                            
                                if(w.locked != win.locked)
                                {
                                    // set it
                                    w.locked = win.locked;
                                }
                            }
                        }
                    }
                }
                
                if(html != null)
                {
                    html.showScrollBars(!win.locked);
                }
            }
            
            private function AddTicker(ticker:String):Canvas
            {
                if(ticker == null || ticker == "")
                    return null;
                if(!listTickers.contains(ticker.toUpperCase()))
                {
                    listTickers.addItem(ticker.toUpperCase());
                    txtTicker.text = "";
                    // add a tab page for it
                    var c:Canvas = new Canvas();
                    for each(var url:String in listURLs)
                    {
                        AddTickerWindow(c, ticker, url);
                    }
                    c.label = ticker.toUpperCase();
                    
                    tabMain.addChild(c);    
                    return c;
                }
                return null;
            }
            
            private function handleAddNote(e:ContextMenuEvent):void
            {
                var c:Canvas = (e.contextMenuOwner as TabNavigator).selectedChild as Canvas;
                if(tabMain.mouseX > 0 && tabMain.mouseY > 0)
                {
                    addNoteWindow(c, "", tabMain.mouseX, tabMain.mouseY).focusText();
                }
                else
                    addNoteWindow(c).focusText();                    
            }
            
            private function addNoteWindow(c:Canvas, note:String = "", x:int = 0, y:int = 0, width:int = 0, height:int = 0):DialogNote
            {
                var win:DialogNote = new DialogNote();
                
                win.setNote(note);
                win.x = x;
                win.y = y;
                if(width > 0)
                    win.width = width;
                if(height > 0)
                    win.height = height;
                c.addChild(win);
                return win;
            }
            
            private function handleDisplayMenu(e:ContextMenuEvent):void
            {
                var win:ResizableWindow = e.contextMenuOwner as ResizableWindow;
                var scaleStr:String = ((win.scaleX * 100) as int).toString() + "%";
                
                for each(var item:ContextMenuItem in win.contextMenu.items)
                {
                    if(item.submenu != null)
                    {
                        for each (var subitem:ContextMenuItem in item.submenu.items)
                        {
                            if(subitem.label == scaleStr)
                                subitem.checked = true;
                            else
                                subitem.checked = false;
                        }
                    }
                }
            }
            
            private function handleRefreshSelect(e:ContextMenuEvent):void
            {
                var win:ResizableWindow = e.contextMenuOwner as ResizableWindow;
                var html:CustomHTML = (win.getChildAt(0) as CustomHTML);
                html.htmlLoader.reload();
                html.setVScrollPos(parseInt(prefsXML.html.(@href == html.tag.url.toString())[0].@verticalScroll));
                html.setHScrollPos(parseInt(prefsXML.html.(@href == html.tag.url.toString())[0].@horizontalScroll));
            }
            
            private function handleMoveToZero(e:ContextMenuEvent):void
            {
                var win:ResizableWindow = e.contextMenuOwner as ResizableWindow;
                if(win == null)
                    return;
                win.x = 0;
                win.y = 0;
            }
            
            private function handleOpenURL(e:ContextMenuEvent):void
            {
                var win:ResizableWindow = e.contextMenuOwner as ResizableWindow;
                var html:CustomHTML = (win.getChildAt(0) as CustomHTML);
                if(html != null)
                {
                    var urlReq:URLRequest = new URLRequest();
                    urlReq.url = html.location;
                    
                    navigateToURL(urlReq);
                }                
            }
            
            private function handleScaleSelect(e:ContextMenuEvent):void
            {
                var win:ResizableWindow = e.contextMenuOwner as ResizableWindow;
                var html:CustomHTML = (win.getChildAt(0) as CustomHTML);
                
                var text:String = (e.target as ContextMenuItem).caption;
                var scalePct:Number = parseFloat(text.substr(0, text.indexOf("%")));
                
                if(scalePct > 99)
                {
                    win.scaleX = 1;
                    win.scaleY = 1;
                }
                if(scalePct > 0)
                {
                    win.scaleX = 1.0 * scalePct / 100.0;
                    win.scaleY = 1.0 * scalePct / 100.0;
                }
            }
            
            private function handleListKeyDown(e:KeyboardEvent):void
            {
                var list:List = e.currentTarget as List;
                if(e.keyCode == Keyboard.DELETE)
                {
                    listDelete(list);
                }
            }
            
            private function listDelete(list:List):void
            {
                // delete selected
                for each(var item:Object in list.selectedItems)
                {
                    deleteItemFromList(list,item);
                }
            }
            
            private function deleteItemFromList(list:List, item:Object, deep:Boolean = true):void
            {
                (list.dataProvider as ArrayCollection).removeItemAt((list.dataProvider as ArrayCollection).getItemIndex(item));
                if(!deep)
                    return;
                if(list.dataProvider == listTickers)
                {
                    // remove tab
                    for each(var c:Canvas in tabMain.getChildren())
                    {
                        if(c == tabMain.getChildAt(0))
                            continue;
                        if(c.label == item.toString())
                        {
                            // save notes if there are any
                            for each(var o:Object in c.getChildren())
                            {
                                if(!(o is DialogNote))
                                    continue;
                                var note:DialogNote = o as DialogNote;
                                if(prefsXML.oldNotes.length() == 0)
                                    prefsXML.appendChild(new XML("<oldNotes/>"));
                                var noteXML:XML = new XML('<note tickerSymbol="' + item.toString() + '" text="' + note.getNote() + '"/>')
                                prefsXML.oldNotes.appendChild(noteXML);
                                addOldNoteToWindow(noteXML);
                            }
                            tabMain.removeChild(c);
                        }        
                    }    
                }
                else if(list.dataProvider == listURLs)
                {
                    // remove url window from each tab    
                    var url:String = item.toString();
                    for each(c in tabMain.getChildren())
                    {
                        if(c == tabMain.getChildAt(0))
                            continue;
                        for each(var win:ResizableWindow in c.getChildren())
                        {
                            if((win.getChildAt(0) is CustomHTML) &&(win.getChildAt(0) as CustomHTML).tag.url.toString() == url)
                            {                            
                                c.removeChildAt(c.getChildIndex(win));
                            }
                        }        
                    }    
                }
                else if(list.dataProvider == listLocalURLs)
                {
                    // remove url window from each tab    
                    url = item.toString();
                    c = tabMain.getChildAt(0) as Canvas;
                    for (var i:int = 0; i < c.getChildren().length; ++i)
                    {
                        if(!(c.getChildAt(i) is ResizableWindow))
                            continue;
                        win = c.getChildAt(i) as ResizableWindow;
                        if((win.getChildAt(0) is CustomHTML) && (win.getChildAt(0) as CustomHTML).tag.url.toString() == url)
                        {                            
                            c.removeChildAt(c.getChildIndex(win));
                        }
                    }        
                }    
            }
            
            private function handleWindowScaleUpdate(e:Event):void
            {
                if(!loaded)
                    return;
                var w:ResizableWindow = e.currentTarget as ResizableWindow;
                if(w == null || !w.initialized)
                    return;
                    
                var html:CustomHTML = w.getChildAt(0) as CustomHTML;
                
                var url:String;
                if(html == null)
                    url = w.title;
                else
                    url = html.tag.url.toString();
                if(url == null)
                    return;    
                
                if(prefsXML.html.(@href == url).length() == 0)
                    prefsXML.appendChild(new XML("<html href=\"" + url + "\"/>"));
                    
                prefsXML.html.(@href == url)[0].@scaleX = w.scaleX;
                prefsXML.html.(@href == url)[0].@scaleY = w.scaleY;
                
                if(w.parent == tabMain.getChildAt(0))
                {
                    // save only this window's position info if it's on the first page
                    return;    
                } 
                // else
                // find all other windows with this tag url and set their position too.
                for each(var c:Canvas in tabMain.getChildren())
                {
                    if(c == tabMain.getChildAt(0))
                        continue;
                    for each(var win:ResizableWindow in c.getChildren())
                    {
                        if(win is DialogNote)
                            continue;
                        if(win != w && (win.getChildAt(0) as CustomHTML) && (win.getChildAt(0) as CustomHTML).tag.url.toString() == url)
                        {                    
                            win.scaleX = w.scaleX;
                            win.scaleY = w.scaleY;
                        }
                    }
                }
            }
            
            private function handleWindowUpdate(e:Event):void
            {
                if(!loaded)
                    return;
                var w:ResizableWindow = e.currentTarget as ResizableWindow;
                if(w == null || !w.initialized)
                    return;
                    
                var html:CustomHTML = w.getChildAt(0) as CustomHTML;
                
                var url:String;
                if(html == null)
                    url = w.title;
                else
                    url = html.tag.url.toString();
                if(url == null)
                {
                    return;    
                }
                
                if(prefsXML.html.(@href == url).length() == 0)
                {
                    prefsXML.appendChild(new XML("<html href=\"" + url + "\"/>"));
                }
                    
                prefsXML.html.(@href == url)[0].@x = w.x;
                prefsXML.html.(@href == url)[0].@y = w.y;
                prefsXML.html.(@href == url)[0].@width = w.width / w.scaleX;
                prefsXML.html.(@href == url)[0].@height = w.height / w.scaleY;
                if(html != null)
                {
                    prefsXML.html.(@href == url)[0].@verticalScroll = html.verticalScrollPosition;
                    prefsXML.html.(@href == url)[0].@horizontalScroll = html.horizontalScrollPosition;
                }
                
                if(w.parent == tabMain.getChildAt(0))
                {
                    // save only this window's position info if it's on the first page
                    return;    
                } 
                // else
                // find all other windows with this tag url and set their position too.
                for each(var c:Canvas in tabMain.getChildren())
                {
                    if(c == tabMain.getChildAt(0))
                        continue;
                    for each(var win:ResizableWindow in c.getChildren())
                    {
                        if(win is DialogNote)
                            continue;
                        if(win != w && (win.getChildAt(0) as CustomHTML) && (win.getChildAt(0) as CustomHTML).tag.url.toString() == url)
                        {                    
                            win.x = w.x;
                            win.y = w.y;
                            win.width = w.width;
                            win.height = w.height;
                            (win.getChildAt(0) as CustomHTML).setVScrollPos(html.verticalScrollPosition);
                            (win.getChildAt(0) as CustomHTML).setHScrollPos(html.horizontalScrollPosition);
                        }
                    }
                }
            }
            
            private function handleTabChange(e:Event):void
            {
                try
                {
                    // refresh the each titleWindow's scroll position
                    var c:Canvas = (e.currentTarget as TabNavigator).selectedChild as Canvas;
                    for(var i:int = 0; i < c.getChildren().length; ++i)
                    {
                        if(!(c.getChildAt(i) is ResizableWindow) || c.getChildAt(i) is DialogNote)
                            continue;
                        
                        var win:ResizableWindow = c.getChildAt(i) as ResizableWindow;
                        var html:CustomHTML = win.getChildAt(0) as CustomHTML;
                        var url:String;
                        if(html == null)
                            url = win.title;
                        else 
                            url = html.tag.url.toString();
                        html.loadDelayedLocation();
                        html.setVScrollPos(parseInt(prefsXML.html.(@href == url)[0].@verticalScroll));
                        html.setHScrollPos(parseInt(prefsXML.html.(@href == url)[0].@horizontalScroll));
                    }
                }
                catch(e:Error)
                {
                    
                }
            }
            
            private function handleClosing(e:Event):void
            {
                savePreferences();
            }    
            
            private function savePreferences():void
            {
                prefsXML.tickerSymbol = new XMLList();
                for each(var s:String in listTickers)
                {
                    if(prefsXML.tickerSymbol.(text() == s).length() == 0)
                        prefsXML.appendChild(new XML("<tickerSymbol>" + s + "</tickerSymbol>"));
                }
                prefsXML.tickerURL = new XMLList();
                for each(s in listURLs)
                {
                    if(prefsXML.tickerURL.(text() == s).length() == 0)
                        prefsXML.appendChild(new XML("<tickerURL>" + s + "</tickerURL>"));
                }
                prefsXML.localURL = new XMLList();
                for each(s in listLocalURLs)
                {
                    if(prefsXML.localURL.(text() == s).length() == 0)
                        prefsXML.appendChild(new XML("<localURL>" + s + "</localURL>"));
                }
                
                prefsXML.window.@x = this.nativeWindow.x;
                prefsXML.window.@y = this.nativeWindow.y;
                prefsXML.window.@width = this.nativeWindow.width;
                prefsXML.window.@height = this.nativeWindow.height;
                
                if(oldNotesWindow != null)
                {
                    prefsXML.oldNotesWindow.@x = oldNotesWindow.x;
                    prefsXML.oldNotesWindow.@y = oldNotesWindow.y;
                    prefsXML.oldNotesWindow.@width = oldNotesWindow.width;
                    prefsXML.oldNotesWindow.@height = oldNotesWindow.height;
                }
                                
                // save any note windows
                var note:DialogNote = null;
                prefsXML.window.note = new XMLList();
                for each(var canvas:Canvas in tabMain.getChildren())
                {
                    prefsXML.tickerSymbol.(text() == canvas.label).note = new XMLList();
                    for each(var o:Object in canvas.getChildren())
                    {
                        if(o is DialogNote && (o as DialogNote).title != "Old Ticker Notes")
                        {
                            note = o as DialogNote;
                            if(canvas == tabMain.getChildAt(0))
                            {
                                prefsXML.window.appendChild(new XML('<note text="' + note.getNote() + 
                                        '" noteX="' + note.x + '" noteY="' + note.y + 
                                        '" noteWidth="' + note.width + '" noteHeight="' + note.height + '"/>'));
                            }
                            else
                            {
                                prefsXML.tickerSymbol.(text() == canvas.label).appendChild(new XML('<note text="' + note.getNote() + 
                                        '" noteX="' + note.x + '" noteY="' + note.y + 
                                        '" noteWidth="' + note.width + '" noteHeight="' + note.height + '"/>'));
                            }
                        }
                    }
                }
                
                var outputString:String = '<?xml version="1.0" encoding="utf-8"?>\n';
                outputString += prefsXML.toXMLString();
                outputString = outputString.replace(/\n/g, File.lineEnding);
                stream = new FileStream();
                stream.open(prefsFile, FileMode.WRITE);
                stream.writeUTFBytes(outputString);
                stream.close();
            }
            
            private function loadPreferences():void
            {
                stream = new FileStream();
                if (prefsFile.exists) 
                {
                    stream.open(prefsFile, FileMode.READ);
                    prefsXML = XML(stream.readUTFBytes(stream.bytesAvailable));
                    stream.close();
                    
                    // load preferences
                    // URLS FIRST!!!
                    for each(x in prefsXML.tickerURL)
                        AddURL(x.text().toString());
                    for each(x in prefsXML.localURL)
                        AddLocalURL(x.text().toString());
                        
                    this.nativeWindow.x = prefsXML.window.@x;
                    this.nativeWindow.y = prefsXML.window.@y;
                    this.nativeWindow.width = prefsXML.window.@width;
                    this.nativeWindow.height = prefsXML.window.@height;
                    var configCanvas:Canvas = tabMain.getChildAt(0) as Canvas;
                    if(configCanvas != null)
                    {
                        for each(var noteXML:XML in prefsXML.window.note)
                        {
                            addNoteWindow(configCanvas, noteXML.@text, noteXML.@noteX, noteXML.@noteY, noteXML.@noteWidth, noteXML.@noteHeight);
                        }
                    }
                    
                    for each(var x:XML in prefsXML.tickerSymbol)
                    {
                        var tickerCanvas:Canvas = AddTicker(x.text().toString());
                        if(tickerCanvas != null)
                        {
                            for each(noteXML in x.note)
                            {
                                addNoteWindow(tickerCanvas, noteXML.@text, noteXML.@noteX, noteXML.@noteY, noteXML.@noteWidth, noteXML.@noteHeight);
                            }
                        }                            
                    }
                    
                    // load static window configuration
                    for each(var o:Object in (tabMain.getChildAt(0) as Canvas).getChildren())
                    {
                        if(!(o is ResizableWindow) || o is DialogNote)
                            continue;
                        var win:ResizableWindow = o as ResizableWindow;
                        var html:CustomHTML = win.getChildAt(0) as CustomHTML;
                
                        var url:String;
                        if(html == null)
                            url = win.title;
                        else continue;
                        if(url == null || url.length == 0)
                            continue;
                        
                        if(prefsXML.html.(@href == url).length() == 0)
                            continue;
                        win.x = prefsXML.html.(@href == url)[0].@x;
                        win.y = prefsXML.html.(@href == url)[0].@y;
                        win.locked = prefsXML.html.(@href == url)[0].@locked.toString() == "true";
                        win.width = prefsXML.html.(@href == url)[0].@width;
                        win.height = prefsXML.html.(@href == url)[0].@height;
                        var scaleX:Number = parseFloat(prefsXML.html.(@href == url)[0].@scaleX);
                        var scaleY:Number = parseFloat(prefsXML.html.(@href == url)[0].@scaleY);
                        if(scaleX > 0)
                            win.scaleX = scaleX;
                        if(scaleY > 0)
                            win.scaleY = scaleY;
                    }
                    
                    loadOldNotes();
                }
                else prefsXML = <preferences/>;
                
                
            }
            
            private function loadOldNotes():void
            {
                if(prefsXML.oldNotes.length() == 0)
                    return;
                    
                if(oldNotesWindow == null)
                {
                    oldNotesWindow = new DialogNote();
                    oldNotesWindow.title = "Old Ticker Notes";
                    (tabMain.getChildAt(0) as Canvas).addChild(oldNotesWindow);
                    if(prefsXML.oldNotesWindow.length() > 0)
                    {
                        oldNotesWindow.x = prefsXML.oldNotesWindow.@x;
                        oldNotesWindow.y = prefsXML.oldNotesWindow.@y;
                        oldNotesWindow.width = prefsXML.oldNotesWindow.@width;
                        oldNotesWindow.height = prefsXML.oldNotesWindow.@height;
                    }
                    else
                    {
                        oldNotesWindow.x = 720;
                        oldNotesWindow.y = 20;
                    }
                }
                else
                    oldNotesWindow.setNote("");
                
                for each(var x:XML in prefsXML.oldNotes.note)
                {
                    addOldNoteToWindow(x);
                }
            }
            
            private function addOldNoteToWindow(noteXML:XML):void
            {
                if(oldNotesWindow == null)
                {
                    oldNotesWindow = new DialogNote();
                    oldNotesWindow.title = "Old Ticker Notes";
                    (tabMain.getChildAt(0) as Canvas).addChild(oldNotesWindow);
                    if(prefsXML.html.(@href == oldNotesWindow.title).length() > 0)
                    {
                        oldNotesWindow.x = prefsXML.html.(@href == oldNotesWindow.title)[0].@x;
                        oldNotesWindow.y = prefsXML.html.(@href == oldNotesWindow.title)[0].@y;
                        oldNotesWindow.width = prefsXML.html.(@href == oldNotesWindow.title)[0].@width;
                        oldNotesWindow.height = prefsXML.html.(@href == oldNotesWindow.title)[0].@height;
                    }
                    else
                    {
                        oldNotesWindow.x = 720;
                        oldNotesWindow.y = 20;
                    }
                }
                
                oldNotesWindow.addLine(noteXML.@tickerSymbol.toString() + " - " + new Date().toDateString() + "- " + noteXML.@text.toString());    
            }
            
            private function handleResetPreferences(e:Event):void
            {    
                for each(var x:XML in prefsXML.html)
                {
                    if(x.@href == "Ticker Symbols:")
                    {
                        prefsXML.html.(@href == x.@href)[0].@x = "10";
                        prefsXML.html.(@href == x.@href)[0].@y = "10";
                        prefsXML.html.(@href == x.@href)[0].@width = "233";
                        prefsXML.html.(@href == x.@href)[0].@height = "247";
                    }
                    else if(x.@href == "Ticker URLs:")
                    {
                        prefsXML.html.(@href == x.@href)[0].@x = "251";
                        prefsXML.html.(@href == x.@href)[0].@y = "10";
                        prefsXML.html.(@href == x.@href)[0].@width = "368";
                        prefsXML.html.(@href == x.@href)[0].@height = "247";
                    }
                    else if(x.@href == "Local Windows:")
                    {
                        prefsXML.html.(@href == x.@href)[0].@x = "10";
                        prefsXML.html.(@href == x.@href)[0].@y = "265";
                        prefsXML.html.(@href == x.@href)[0].@width = "336";
                        prefsXML.html.(@href == x.@href)[0].@height = "204";
                    }
                    else
                    {                        
                        prefsXML.html.(@href == x.@href)[0].@x = "0";
                        prefsXML.html.(@href == x.@href)[0].@y = "0";
                        prefsXML.html.(@href == x.@href)[0].@width = "400";
                        prefsXML.html.(@href == x.@href)[0].@height = "400";
                    }
                }
                
                for each (var c:Canvas in tabMain.getChildren())
                {                    
                    for each(var o:Object in c.getChildren())
                    {
                        if(!(o is ResizableWindow))
                            continue;
                        if((o as ResizableWindow).title == "Ticker Symbols:" || 
                            (o as ResizableWindow).title == "Ticker URLs:" ||
                            (o as ResizableWindow).title == "Local Windows:")
                            continue;
                        (o as ResizableWindow).x = 0;
                        (o as ResizableWindow).y = 0;
                        (o as ResizableWindow).width = 400;
                        (o as ResizableWindow).height = 400;                        
                    }
                }
            }
            
            public function pad(number:int, width:int):String 
            {
               var ret:String = ""+number;
               while( ret.length < width )
                   ret="0" + ret;
               return ret;
            }
            
            private function backupPrefs():void
            {
                savePreferences();
                var now:Date = new Date();
                var savePrefName:String = "clearedPrefs-" + now.fullYear + "." + pad(now.month, 2) + "." + 
                            pad(now.date, 2) + "." + pad(now.hours, 2) + pad(now.minutes, 2) + pad(now.seconds, 2) + ".xml"; 
                prefsFile.copyTo(File.applicationStorageDirectory.resolvePath(savePrefName), true); 
            }
            
            private function handleResetAll(e:Event):void
            {
                // save current prefs just in case this was an accident
                backupPrefs();
                
                resetAll();
            }
            
            private function resetAll():void
            {
                // clear all stocks
                while(listTickers.length > 0)
                {
                    deleteItemFromList(lstTickers, listTickers[0]);
                }
                // clear all URLs
                while(listURLs.length > 0)
                {
                    deleteItemFromList(lstTickerURLs, listURLs[0], false);
                }
                
                // clear all localURLS
                while(listLocalURLs.length > 0)
                {
                    deleteItemFromList(lstLocalURLs, listLocalURLs[0]);
                }
                
                for each(var o:Object in (tabMain.getChildAt(0) as Canvas).getChildren())
                {
                    if(o is DialogNote)
                        (tabMain.getChildAt(0) as Canvas).removeChild(o as DialogNote);
                }
                
                // reset prefs
                stream = new FileStream();
                stream.open(prefsFile, FileMode.WRITE);
                stream.writeUTFBytes("");
                stream.close();
                
                prefsXML = <preferences/>;
                
                Alert.show("All preferences have been cleared.");
            }
            
            private function handleSavePreferences(e:Event):void
            {
                var outFile:File = File.applicationStorageDirectory;
                
                outFile.addEventListener(Event.SELECT, handleSaveSelect);
                outFile.browseForSave("Save Preferences");//, ([new FileFilter("XML Files", "*.xml")]));                
            }
            
            private function handleSaveSelect(e:Event):void
            {
                savePreferences();
                var file:File = e.target as File;
                if(!file.extension || file.extension != "xml")
                {
                    file.nativePath += ".xml";
                } 
                // save to outfile
                prefsFile.copyTo(file, true); 
            }
            
            private function handleClearOldNotes(e:Event):void
            {
                backupPrefs();
                prefsXML.oldNotes = new XMLList();
                if(oldNotesWindow != null)
                {
                    oldNotesWindow.setNote("");
                }    
            }
            
            private function handleLoadPreferences(e:Event):void
            {
                var sourceFile:File = File.applicationStorageDirectory;
                
                sourceFile.addEventListener(Event.SELECT, handleLoadSelect);
                sourceFile.browseForOpen("Load Preferences", ([new FileFilter("XML Files", "*.xml")]));
            }
            
            private function handleLoadSelect(e:Event):void
            {
                var file:File = e.target as File;
                backupPrefs();
                // save to outfile
                resetAll();
                file.copyTo(File.applicationStorageDirectory.resolvePath("preferences.xml"), true); 
                prefsFile = File.applicationStorageDirectory.resolvePath("preferences.xml");
                loadPreferences();    
            }
            
            private function handleMenuClick(e:MenuEvent):void
            {
                if(!(e.item is XML))
                    return;
                var handler:String = (e.item as XML).@clickHandler;
                if(handler.length > 0)
                {
                    this[handler](new Event("click"));
                }
            }
            
            private function handleClickPrefOption(e:MenuEvent):void
            {
                if(!(e.item is XML))
                    return;
                var handler:String = (e.item as XML).@click;
                if(handler.length > 0)
                {
                    this[handler](new Event("click"));
                }
            }
            
            private function handleAbout():void
            {
                var aboutdlg:DialogAbout = new DialogAbout();
                PopUpManager.addPopUp(aboutdlg, this, true);
                PopUpManager.centerPopUp(aboutdlg);
            }
            
            private function handleIssue():void
            {
                var issueDlg:DialogSendIssue = new DialogSendIssue();
                PopUpManager.addPopUp(issueDlg, this, true);
                PopUpManager.centerPopUp(issueDlg);
            }
            
            /*private function scrollLogToBottom():void
            {
                txtLog.verticalScrollPosition = txtLog.getRect(txtLog).bottom;
            }
            
            public function Log(msg:String):void
            {
                txtLog.text += msg + "\n";
                callLater(scrollLogToBottom);
            }*/
        ]]>
    </mx:Script>
    <mx:XML format="e4x" id="mainMenuData">
         <root>
            <menuitem label="File">
                <menuitem label="Clear Preferences" enabled="true" clickHandler="handleResetPreferences"/>
            </menuitem>
            
        </root>
     </mx:XML>
     <mx:XMLList id="prefChoices">
        <node label="Save Preferences..." click="handleSavePreferences"/>
        <node label="Load Preferences..." click="handleLoadPreferences"/>
        <node label="Clear Old Notes" click="handleClearOldNotes"/>
        <node label="Reset Window Positions" click="handleResetPreferences"/>
        <node label="Clear Everything (backup is saved)" click="handleResetAll"/>
        
    </mx:XMLList>
    <mx:HBox width="100%" height="20" horizontalAlign="right">
        <mx:PopUpMenuButton label="Preferences" height="20" dataProvider="{prefChoices}" labelField="@label" itemClick="handleClickPrefOption(event);" openAlways="true"/>
        <mx:Button label="Comments or Questions?" height="20" click="handleIssue()"/>
        <mx:Button label="About..." height="20" click="handleAbout()"/>
    </mx:HBox>
    <mx:TabNavigator id="tabMain" width="100%" height="100%" change="handleTabChange(event)">
        <mx:Canvas label="Config" width="100%" height="100%">
            <ns1:ResizableWindow lockChanged="handleWindowLockChanged(event)" movable="true" x="10" y="10" width="233" height="247" 
                layout="absolute" title="Ticker Symbols:" resize="handleWindowUpdate(event)" dragEnd="handleWindowUpdate(event)"
                mouseUp="handleWindowUpdate(event)">
                <mx:List id="lstTickers" dataProvider="{listTickers}" width="100%" bottom="26" top="0" keyDown="handleListKeyDown(event)"></mx:List>
                <mx:TextInput id="txtTicker" keyDown="handleAddTicker(event)" bottom="2" right="55" left="2"/>
                <mx:Button click="AddTicker(txtTicker.text)" label="Add" width="50" bottom="2" right="4"/>
            </ns1:ResizableWindow>
            <ns1:ResizableWindow lockChanged="handleWindowLockChanged(event)" movable="true" x="251" y="10" width="368" height="247" 
                layout="absolute" title="Ticker URLs:" resize="handleWindowUpdate(event)" dragEnd="handleWindowUpdate(event)"
                mouseUp="handleWindowUpdate(event)" horizontalScrollPolicy="off" verticalScrollPolicy="off">
                <mx:List id="lstTickerURLs" dataProvider="{listURLs}" x="0" width="100%" top="0" bottom="26" keyDown="handleListKeyDown(event)"></mx:List>
                <mx:TextInput id="txtTickerURL" bottom="2" keyDown="handleAddURL(event)" left="2" right="55">
                    <mx:toolTip>NOTE: Use \{ticker\} to denote the location of the ticker symbol in the URL</mx:toolTip>
                </mx:TextInput>
                <mx:Button click="AddURL(txtTickerURL.text)" label="Add" width="50" bottom="2" right="4"/>
            </ns1:ResizableWindow>
            <ns1:ResizableWindow lockChanged="handleWindowLockChanged(event)" movable="true" id="pnlLocal" x="10" y="265" width="336" height="204" 
                layout="absolute" title="Local Windows:" resize="handleWindowUpdate(event)" dragEnd="handleWindowUpdate(event)"
                mouseUp="handleWindowUpdate(event)">
                <mx:List id="lstLocalURLs" dataProvider="{listLocalURLs}" x="0" width="100%" top="0" bottom="26" keyDown="handleListKeyDown(event)"></mx:List>
                <mx:TextInput id="txtLocalURL" bottom="2" keyDown="handleAddLocalURL(event)" right="55" left="2"/>
                <mx:Button click="AddLocalURL(txtLocalURL.text)" label="Add" width="50" bottom="2" right="4"/>
            </ns1:ResizableWindow>
        </mx:Canvas>
    </mx:TabNavigator>
    
    
</mx:WindowedApplication>