<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" horizontalAlign="left"
    creationComplete="setup(10000);" viewSourceURL="srcview/index.html">
    <mx:Script>
        <![CDATA[
            import flash.sampler.getInvocationCount;
            import flash.utils.getTimer;
            import mx.core.UIComponent;
            
            [Bindable] public var array1:Array;
            [Bindable] public var array2:Array;
            [Bindable] public var full:Array;
            
            [Bindable] public var uniqueArray1:Array;
            [Bindable] public var uniqueArray2:Array;
            [Bindable] public var intersection:Array;
            [Bindable] public var union:Array;
            
            private function setup(numItems:Number):void {
                var start:int = getTimer();
                full = generateFullCollection(numItems);
                var duration:int = getTimer() - start;
                writeLog("Generating " + numItems + " items: " + duration + "ms");
                
                hashCount = bitmapCount = byteCount = 0;
                totalBitmapDuration = totalHashDuration = totalByteDuration = 0;
                
                bitmapProcessor.setFullArray(full);
                hashProcessor.setFullArray(full);
                byteProcessor.setFullArray(full);
            }
            
            private var bitmapProcessor:ArrayBitmapProcessor = new ArrayBitmapProcessor();
            private var hashProcessor:ArrayHashProcessor = new ArrayHashProcessor();
            private var byteProcessor:ArrayByteArrayProcessor = new ArrayByteArrayProcessor();
            
            private var bitmapCount:Number=0;
            private var totalBitmapDuration:Number = 0;
            
            private function testBitmap():void {
                imageHolder.removeAllChildren();
                
                var start:int = getTimer();
                
                array1 = bitmapProcessor.filter(filterRandomly);
                
                if(showImageCheck.selected)
                    addBitmapToScreen(bitmapProcessor.currentBitmap);
                
                array2 = bitmapProcessor.filter(filterRandomly);
                
                if(showImageCheck.selected)
                    addBitmapToScreen(bitmapProcessor.currentBitmap);
                    
                var results:Array = bitmapProcessor.process(array1, array2);
                
                if(showImageCheck.selected)
                    addBitmapToScreen(bitmapProcessor.currentBitmap);
                                    
                uniqueArray1 = results[0]
                uniqueArray2 = results[1];
                intersection = results[2];
                union = results[3];
                
                var duration:int = getTimer() - start;

                totalBitmapDuration += duration;
                bitmapCount++;
                
                writeLog("Bitmap test: " + duration + "ms (avg: " + int(totalBitmapDuration/bitmapCount) + "ms)");
            }
            
            private function addBitmapToScreen(bitmapData:BitmapData):void {
                var bitmap:Bitmap = new Bitmap(bitmapData);
                var ui:UIComponent = new UIComponent();
                ui.addChild(bitmap);
                ui.width = bitmapData.width;
                ui.height = bitmapData.height;
                
                imageHolder.addChild(ui);
            }
            
            private var hashCount:Number=0;
            private var totalHashDuration:Number = 0;
            
            private function testHash():void {
                var start:int = getTimer();
                
                array1 = hashProcessor.filter(filterRandomly);
                array2 = hashProcessor.filter(filterRandomly);
                
                var results:Array = hashProcessor.process(array1, array2);
                uniqueArray1 = results[0]
                uniqueArray2 = results[1];
                intersection = results[2];
                union = results[3];
                
                var duration:int = getTimer() - start;
                
                totalHashDuration += duration;
                hashCount++;
                
                writeLog("Hashmap test: " + duration + "ms (avg: " + int(totalHashDuration/hashCount) + "ms)");
            }
            
            private var byteCount:Number=0;
            private var totalByteDuration:Number = 0;
            
            private function testByte():void {
                var start:int = getTimer();
                
                array1 = byteProcessor.filter(filterRandomly);
                array2 = byteProcessor.filter(filterRandomly);
                
                var results:Array = byteProcessor.process(array1, array2);
                uniqueArray1 = results[0]
                uniqueArray2 = results[1];
                intersection = results[2];
                union = results[3];
                
                var duration:int = getTimer() - start;
                
                totalByteDuration += duration;
                byteCount++;
                
                writeLog("ByteArray test: " + duration + "ms (avg: " + int(totalByteDuration/byteCount) + "ms)");
            }
            
            private function testForLoop():void {
                var start:int = getTimer();
                
                array1 = full.filter(filterRandomly);
                array2 = full.filter(filterRandomly);
                
                var results:Array = runForLoopTest(array1, array2);
                uniqueArray1 = results[0]
                uniqueArray2 = results[1];
                intersection = results[2];
                union = results[3];
                
                var duration:int = getTimer() - start;
                writeLog("For loop test: " + duration + "ms");
            }
            
            private function runForLoopTest(array1:Array, array2:Array):Array {
                var unique1:Array = [];
                var unique2:Array = [];
                var intersection:Array = [];
                var union:Array = [];
                
                var n:int = full.length;
                for(var i:int=0; i<n; i++) {
                    var item:Object = full[i];
                    var inArray1:Boolean = array1.indexOf(item) != -1;
                    var inArray2:Boolean = array2.indexOf(item) != -1;
                    
                    if(inArray1 || inArray2) {
                        union.push(item);
                    }
                    
                    if(inArray1 && !inArray2)
                        unique1.push(item);
                    else if(inArray2 && !inArray1)
                        unique2.push(item);
                    else if(inArray1 && inArray2)
                        intersection.push(item);
                }
                
                return [unique1, unique2, intersection, union];
            }
            
            private function generateFullCollection(numItems:Number):Array {
                var items:Array = [];
                
                for(var i:int=0; i<numItems; i++) {
                    //doesn't seem to make a difference for any of the algorithms
                    //items.push(new StronglyTypedObject("item " + i));
                    items.push({label:"item " + i});
                    //items.push({});
                }
                
                return items;
            }
            
            private function filterRandomly(item:Object, index:int, array:Array):Boolean {
                return Math.random() >= .5;
            }
            
            private function writeLog(text:String):void {
                log.text += (text + "\n");
                log.verticalScrollPosition = log.maxVerticalScrollPosition;
            }
            
        ]]>
    </mx:Script>
    
    <mx:HBox>
        <mx:Label text="Total full array size:" />
        <mx:ComboBox id="combo"
            change="setup(Number(combo.selectedItem.value))" selectedIndex="3">
            <mx:dataProvider>
                <mx:Array>
                    <mx:Object label="10" value="10" />
                    <mx:Object label="100" value="146" />
                    <mx:Object label="1,000" value="1000" />
                    <mx:Object label="10,000" value="10000" />
                    <mx:Object label="100,000" value="100000" />
                    <mx:Object label="1 million" value="1000000" />
                    <mx:Object label="2 million" value="2000000" />
                    <mx:Object label="5 million" value="5000000" />
                </mx:Array>
            </mx:dataProvider>
        </mx:ComboBox>
        
        <mx:Button label="For loop Test" click="testForLoop()" enabled="{combo.selectedIndex &lt; 4 || OKCheck.selected}" />
        <mx:Button label="Hashmap Test" click="testHash()" />
        <mx:Button label="ByteArray Test" click="testByte()" />
        <mx:Button label="Bitmap Test" click="testBitmap()" />
        <mx:CheckBox label="show generated images" id="showImageCheck" />
    </mx:HBox>
    
    <mx:HBox width="100%" visible="{combo.selectedIndex >= 4}">
        <mx:Label color="#ff0000" fontSize="15" fontWeight="bold" text="WARNING:" />
        <mx:VBox width="100%">
            <mx:Text width="100%" text="running this many items using the For Loop Test will probably cause your browser to become unresponsive and may result in the browser crashing." />
            <mx:CheckBox label="That's OK, I'm crazy, re-enable the button so I can run it anyway" id="OKCheck" />
        </mx:VBox>
    </mx:HBox>
    
    <mx:HBox>
        <mx:Panel title="Full Array" width="150">
            <mx:DataGrid dataProvider="{full}" width="100%" />
        </mx:Panel>
        <mx:Panel title="Filtered Array #1"  width="150" visible="{uniqueArray1 != null}">
            <mx:DataGrid dataProvider="{array1}" width="100%" />
        </mx:Panel>
        <mx:Panel title="Filtered Array #2"  width="150" visible="{uniqueArray2 != null}">
            <mx:DataGrid dataProvider="{array2}" width="100%" />
        </mx:Panel>
        <mx:TextArea height="100%" width="250" id="log" />
    </mx:HBox>
    
    <mx:HBox visible="{uniqueArray1 != null}">
        <mx:Panel title="Unique items in #1" width="150">
            <mx:DataGrid dataProvider="{uniqueArray1}" width="100%" />
        </mx:Panel>
        <mx:Panel title="Unique items in #2" width="150">
            <mx:DataGrid dataProvider="{uniqueArray2}" width="100%" />
        </mx:Panel>
        <mx:Panel title="Intersection" width="150" visible="{intersection != null}">
            <mx:DataGrid dataProvider="{intersection}" width="100%" />
        </mx:Panel>
        <mx:Panel title="Union" width="150" visible="{union != null}">
            <mx:DataGrid dataProvider="{union}" width="100%" />
        </mx:Panel>
    </mx:HBox>
    
    <mx:HBox id="imageHolder" />
    
</mx:Application>