<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication 
    xmlns:mx="http://www.adobe.com/2006/mxml" 
    xmlns:net="flash.net.*"
    xmlns:comp="components.*"
    layout="vertical"
    backgroundGradientAlphas="[1.0, 1.0]"
    backgroundGradientColors="[#F4F4F4, #E0E0E0]"
    paddingBottom="10" paddingLeft="10" paddingRight="10" paddingTop="10"
    verticalScrollPolicy="off" horizontalScrollPolicy="off"
    creationComplete="init()"
    >

    <mx:Script>
    <![CDATA[
    
    import mx.controls.ComboBox;
    import mx.containers.HBox;
    import mx.utils.Base64Encoder;    
    import mx.core.WindowedApplication;
    import mx.containers.VBox;
    import mx.controls.Button;
    import mx.collections.ArrayCollection;
    import mx.controls.Alert;
    import mx.events.FlexEvent;
    import mx.managers.DragManager;
    import flash.events.*;
    import flash.desktop.NativeDragManager;
    import flash.desktop.NativeDragActions;
    import flash.desktop.Clipboard;
    import flash.desktop.ClipboardFormats;
    import flash.filesystem.File;
    import flash.events.FileListEvent;
    import flash.net.*;


    private var urlRequest:URLRequest;
    private var fileChooser:File = new File;

    [Bindable]
    private var upload_url:String = '';    
    
    [Bindable]
    private var upload_username:String = '';    
    
    [Bindable]
    private var upload_password:String = '';    
    
    [Bindable]
    private var upload_hotfolder:String = '';
    
    [Bindable]    
    private var arrayCollection:ArrayCollection = new ArrayCollection;

    [Bindable]
    private var tagdefs:Array =
    [
        { label: 'Headline', data: 'Headline' },
        { label: 'Keywords', data: 'Keywords' },
        { label: 'Person', data: 'Person' }
    ];
    
    [Bindable]
    private var tagmodes:Array = 
    [
        { label: 'Default value',  data: 'defaulttag' },
        { label: 'Add value',      data: 'addtag'     },
        { label: 'Replace values', data: 'settag'     }
    ];

    [Bindable]
    private var upload_fv_1_field:String = '';        
    
    [Bindable]
    private var upload_fv_1_value:String = '';        
    
    [Bindable]
    private var upload_fv_1_mode:String = '';        
    
    [Bindable]
    private var upload_fv_2_field:String = '';        
    
    [Bindable]
    private var upload_fv_2_value:String = '';        
    
    [Bindable]
    private var upload_fv_2_mode:String = '';        
    
    [Bindable]
    private var upload_fv_3_field:String = '';        
    
    [Bindable]
    private var upload_fv_3_value:String = '';        
    
    [Bindable]
    private var upload_fv_3_mode:String = '';        
    

    private function init():void
    {
        // Display version number in title bar
        
        var appXML:XML = NativeApplication.nativeApplication.applicationDescriptor;
        var air:Namespace = appXML.namespaceDeclarations()[ 0 ];
        this.title = appXML.air::initialWindow.air::title + ' ' + appXML.air::version;
        
        addEventListener(NativeDragEvent.NATIVE_DRAG_ENTER, this.onDragEnter);
        addEventListener(NativeDragEvent.NATIVE_DRAG_DROP,  this.onDragDrop);

        this.urlRequest = new URLRequest();
        // TODO dynamically read and send actual application version
        this.urlRequest.userAgent = 'DC-X Uploader 0.1.0';
        this.urlRequest.method = URLRequestMethod.POST;
        this.urlRequest.cacheResponse = false;
        this.urlRequest.authenticate = true;

        this.fileChooser.addEventListener(FileListEvent.SELECT_MULTIPLE, this.filesChosen);
        this.fileChooser.addEventListener(Event.SELECT, this.directoryChosen);
        
        this.upload_url = this.getLocalStoreValue('upload_url', 'http://');
        this.upload_username = this.getLocalStoreValue('upload_username', '');
        this.upload_password = this.getLocalStoreValue('upload_password', '');
        this.upload_hotfolder = this.getLocalStoreValue('upload_hotfolder', 'native');

        this.upload_fv_1_field = this.getLocalStoreValue('upload_fieldvalue_1_field', 'Keywords');
        this.upload_fv_1_value = this.getLocalStoreValue('upload_fieldvalue_1_value', '');
        this.upload_fv_1_mode  = this.getLocalStoreValue('upload_fieldvalue_1_mode', 'addtag');
        
        this.upload_fv_2_field = this.getLocalStoreValue('upload_fieldvalue_2_field', 'Keywords');
        this.upload_fv_2_value = this.getLocalStoreValue('upload_fieldvalue_2_value', '');
        this.upload_fv_2_mode  = this.getLocalStoreValue('upload_fieldvalue_2_mode', 'addtag');
        
        this.upload_fv_3_field = this.getLocalStoreValue('upload_fieldvalue_3_field', 'Keywords');
        this.upload_fv_3_value = this.getLocalStoreValue('upload_fieldvalue_3_value', '');
        this.upload_fv_3_mode  = this.getLocalStoreValue('upload_fieldvalue_3_mode', 'addtag');
        
        // TODO restore previous window position and size
    }


    private function vBoxSettingsCreationComplete():void
    {        
        this.setComboBoxSelectedValue(ComboBox_FieldValues_1_Field, this.upload_fv_1_field);                                         
        this.setComboBoxSelectedValue(ComboBox_FieldValues_1_Mode, this.upload_fv_1_mode);                     

        this.setComboBoxSelectedValue(ComboBox_FieldValues_2_Field, this.upload_fv_2_field);                                         
        this.setComboBoxSelectedValue(ComboBox_FieldValues_2_Mode, this.upload_fv_2_mode);                     

        this.setComboBoxSelectedValue(ComboBox_FieldValues_3_Field, this.upload_fv_3_field);                                         
        this.setComboBoxSelectedValue(ComboBox_FieldValues_3_Mode, this.upload_fv_3_mode);                     
    }
        

    private function setComboBoxSelectedValue(cb: ComboBox, val:String):void
    {
        // The Flex ComboBox doesn't have a method setSelectedValue() :-(

        for (var i:int = 0; i < cb.dataProvider.length; i++)
        {
            if (cb.dataProvider[ i ].data === val)
            {
                cb.selectedIndex = i;
                break;
            }
        }
    }
    
    
    private function onDragEnter(event:NativeDragEvent):void
    {
        NativeDragManager.acceptDragDrop(this.dataGrid);
    }


    private function onDragDrop(event:NativeDragEvent):void
    {
        NativeDragManager.dropAction = NativeDragActions.COPY;

        var files:Array = event.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array;
                
        for each (var f:File in files)
           this.addFile(f);
    }


    private function addFile(f:File):void
    {
        // Ignore hidden files
        
        if (f.name.substr(0, 1) === '.')
            return;
        
        if (f.isDirectory)
        {
            if ((f.name === '.') || (f.name === '..'))
                return;
                
            var subfiles:Array = f.getDirectoryListing();
            
            for (var i:int = 0; i < subfiles.length; i++)
                this.addFile(subfiles[ i ]);

            return;
        }
        
        f.addEventListener(Event.COMPLETE, this.completeHandler);
        f.addEventListener(HTTPStatusEvent.HTTP_STATUS, this.httpStatusHandler);
        f.addEventListener(IOErrorEvent.IO_ERROR, this.ioErrorHandler);
        
        this.arrayCollection.addItem
        (
            {
                name: f.name, 
                size: this.formatFileSize(f.size), 
                object: f,
                uploaded: 0
            }
        );        
    }


    private function completeHandler(e:Event):void
    {
        var f:FileReference = FileReference(e.target);
        
        // Find the file in our ArrayCollection...
        
        for each (var item:Object in this.arrayCollection)
        {
            var fp:FileReference = item.object as FileReference;
            
            if (! fp)
                continue;
                
            if (f !== fp)
                continue;

            // ... and mark it as uploaded
                        
            item.uploaded = 1;            
            this.arrayCollection.refresh();
            
            break;    
        }
    }


    private function httpStatusHandler(event:HTTPStatusEvent):void
    {
        Alert.show(event.type + ': ' + event.status, 'Network error during upload');
    }


    private function ioErrorHandler(event:IOErrorEvent):void
    {
        Alert.show(event.type + ': ' + event.text, 'Network error during upload');
    }


    private function startUpload(e:MouseEvent):void
    {
        this.urlRequest.url =
            this.upload_url
            + '?user=' + encodeURIComponent(this.upload_username)
            + '&password=' + encodeURIComponent(this.upload_password)
            + '&hotfolder=' + encodeURIComponent(this.upload_hotfolder)
            + '&tags[0][field]=' + encodeURIComponent(this.upload_fv_1_field)
            + '&tags[0][value]=' + encodeURIComponent(this.upload_fv_1_value)
            + '&tags[0][mode]=' + encodeURIComponent(this.upload_fv_1_mode)
            + '&tags[1][field]=' + encodeURIComponent(this.upload_fv_2_field)
            + '&tags[1][value]=' + encodeURIComponent(this.upload_fv_2_value)
            + '&tags[1][mode]=' + encodeURIComponent(this.upload_fv_2_mode)
            + '&tags[2][field]=' + encodeURIComponent(this.upload_fv_3_field)
            + '&tags[2][value]=' + encodeURIComponent(this.upload_fv_3_value)
            + '&tags[2][mode]=' + encodeURIComponent(this.upload_fv_3_mode)
            ;
        
        for each (var item:Object in this.arrayCollection)
        {
            if (item.uploaded > 0)
                continue;
                
            var f:FileReference = item.object as FileReference;
            
            if (! f)
                continue;

           f.upload(this.urlRequest);
        }
    }
    
    
    private function formatFileSize(numSize:Number):String 
    {
        var result:String;
        
        numSize = Number(numSize / 1000);
        
        result = numSize.toFixed(1).toString() + ' kB';
        
        if (numSize > 1000) 
        {
            numSize = numSize / 1000;
            result = numSize.toFixed(1).toString() + ' MB';
            
            if (numSize > 1000) 
            {
                numSize = numSize / 1000;
                result = numSize.toFixed(1).toString() + ' GB';
            }
        }
                        
        return result;
    }


    private function browseForFiles(event:MouseEvent):void
    {
        this.fileChooser.browseForOpenMultiple('Select files to upload');
    }


    private function browseForDirectory(event:MouseEvent):void
    {
        this.fileChooser.browseForDirectory('Select directory to upload');
    }


    private function removeAllFiles(event:MouseEvent):void
    {
        this.arrayCollection.removeAll();
    }


    private function filesChosen(event:FileListEvent):void
    {
        var fileList:Array = event.files;
            
        for (var i:Number = 0; i < fileList.length; i++)
        {
            var file:File = fileList[ i ] as File;
            
            if (! file)
                continue;
            
            if (file.size > 536870912)
            {
                var vFileSize:String = this.formatFileSize(file.size);
                Alert.show('Max. upload size for a single file is 512 MB.\nSelected file is ' + vFileSize + '.');
            }
            else
            {            
                this.addFile(file);
            }
        }
    }
     

    private function directoryChosen(event:Event):void 
    {
        this.addFile(event.target as File);
    }


    private function uploadButtonEnabled(url:String, hotfolder:String):Boolean
    {
        return ((url !== '') && (url !== 'http://') && (hotfolder !== ''));
    }


    private function saveSettings():void
    {
        this.upload_url = this.TextInput_Settings_URL.text;
        this.upload_username = this.TextInput_Settings_Username.text;
        this.upload_password = this.TextInput_Settings_Password.text;
        this.upload_hotfolder = this.TextInput_Settings_Hotfolder.text;
        
        if ((this.ComboBox_FieldValues_1_Field.selectedIndex >= 0) && (this.ComboBox_FieldValues_1_Mode.selectedIndex >= 0))
        { 
            this.upload_fv_1_field = this.tagdefs[ this.ComboBox_FieldValues_1_Field.selectedIndex ].data;        
            this.upload_fv_1_value = this.TextInput_FieldValues_1_Value.text;
            this.upload_fv_1_mode  = this.tagmodes[ this.ComboBox_FieldValues_1_Mode.selectedIndex ].data;
        }
        
        if ((this.ComboBox_FieldValues_2_Field.selectedIndex >= 0) && (this.ComboBox_FieldValues_2_Mode.selectedIndex >= 0))
        { 
            this.upload_fv_2_field = this.tagdefs[ this.ComboBox_FieldValues_2_Field.selectedIndex ].data;        
            this.upload_fv_2_value = this.TextInput_FieldValues_2_Value.text;
            this.upload_fv_2_mode  = this.tagmodes[ this.ComboBox_FieldValues_2_Mode.selectedIndex ].data;
        }
        
        if ((this.ComboBox_FieldValues_3_Field.selectedIndex >= 0) && (this.ComboBox_FieldValues_3_Mode.selectedIndex >= 0))
        { 
            this.upload_fv_3_field = this.tagdefs[ this.ComboBox_FieldValues_3_Field.selectedIndex ].data;        
            this.upload_fv_3_value = this.TextInput_FieldValues_3_Value.text;
            this.upload_fv_3_mode  = this.tagmodes[ this.ComboBox_FieldValues_3_Mode.selectedIndex ].data;
        }
        
        this.setLocalStoreValue('upload_url', this.upload_url);
        this.setLocalStoreValue('upload_username', this.upload_username);
        this.setLocalStoreValue('upload_password', this.upload_password);
        this.setLocalStoreValue('upload_hotfolder', this.upload_hotfolder);

        this.setLocalStoreValue('upload_fieldvalue_1_field', this.upload_fv_1_field);
        this.setLocalStoreValue('upload_fieldvalue_1_value', this.upload_fv_1_value);
        this.setLocalStoreValue('upload_fieldvalue_1_mode', this.upload_fv_1_mode);
        
        this.setLocalStoreValue('upload_fieldvalue_2_field', this.upload_fv_2_field);
        this.setLocalStoreValue('upload_fieldvalue_2_value', this.upload_fv_2_value);
        this.setLocalStoreValue('upload_fieldvalue_2_mode', this.upload_fv_2_mode);
        
        this.setLocalStoreValue('upload_fieldvalue_3_field', this.upload_fv_3_field);
        this.setLocalStoreValue('upload_fieldvalue_3_value', this.upload_fv_3_value);
        this.setLocalStoreValue('upload_fieldvalue_3_mode', this.upload_fv_3_mode);
        
        this.viewStack.selectedChild = this.vBoxFiles;
    }


    private function cancelSettings():void
    {
        this.TextInput_Settings_URL.text = this.upload_url;
        this.TextInput_Settings_Username.text = this.upload_username;
        this.TextInput_Settings_Password.text = this.upload_password;
        this.TextInput_Settings_Hotfolder.text = this.upload_hotfolder;
        
        this.setComboBoxSelectedValue(ComboBox_FieldValues_1_Field, this.upload_fv_1_field); 
        this.TextInput_FieldValues_1_Value.text = this.upload_fv_1_value;                                        
        this.setComboBoxSelectedValue(ComboBox_FieldValues_1_Mode, this.upload_fv_1_mode);                     
        
        this.setComboBoxSelectedValue(ComboBox_FieldValues_2_Field, this.upload_fv_2_field); 
        this.TextInput_FieldValues_2_Value.text = this.upload_fv_2_value;                                        
        this.setComboBoxSelectedValue(ComboBox_FieldValues_2_Mode, this.upload_fv_2_mode);                     
        
        this.setComboBoxSelectedValue(ComboBox_FieldValues_3_Field, this.upload_fv_3_field); 
        this.TextInput_FieldValues_3_Value.text = this.upload_fv_3_value;                                        
        this.setComboBoxSelectedValue(ComboBox_FieldValues_3_Mode, this.upload_fv_3_mode);                     
        
        this.viewStack.selectedChild = this.vBoxFiles;
    }


    private function setLocalStoreValue(key:String, value:String):void
    {
        var bytes:ByteArray = new ByteArray();
        bytes.writeUTFBytes(value);
        EncryptedLocalStore.setItem(key, bytes);        
    }
    
    
    private function getLocalStoreValue(key:String, default_value:String):String
    {
        var bytes:ByteArray = EncryptedLocalStore.getItem(key);
        
        if (! bytes)
            return default_value;
        
        return bytes.readUTFBytes(bytes.length);
    }
    
    ]]>
    </mx:Script>
    
    <mx:ViewStack id="viewStack"
        width="100%" height="100%"
        >
        
        <mx:VBox id="vBoxFiles"
            width="100%" height="100%"
            >
            
            <mx:DataGrid id="dataGrid" 
                dataProvider="{arrayCollection}" 
                editable="false" 
                alternatingItemColors="[#FFFFFF, #EEEEEE]" 
                themeColor="#FFFFFF" 
                width="100%" height="100%"
                >
                
                <mx:columns>
                    <mx:DataGridColumn 
                        headerText="Filename" 
                        dataField="name"
                        />
                        
                    <mx:DataGridColumn 
                        headerText="Size" 
                        dataField="size" 
                        width="80"
                        />
                        
                    <mx:DataGridColumn 
                        headerText="File progress" 
                        width="150"
                        >
                        
                        <mx:itemRenderer>
                        
                            <mx:Component>
                            
                                <mx:HBox 
                                    paddingLeft="6" paddingRight="6" 
                                    verticalAlign="middle"
                                    >
                                    
                                    <mx:ProgressBar id="prgBar" 
                                        label="" 
                                        height="6" width="100%" 
                                        source="{data.object}" 
                                        barColor="#FF6600"
                                        />
                                            
                                </mx:HBox>
                                
                            </mx:Component>
                            
                        </mx:itemRenderer>
                        
                    </mx:DataGridColumn>
                    
                    <!-- TODO add a column that displays status (new, in progress, done) and allows
                              removing the item or canceling an upload in progress -->
                    
                </mx:columns>
                
            </mx:DataGrid>
        
            <mx:HBox 
                width="100%" 
                >
                
                <mx:Button id="buttonSelectFiles" 
                    label="Add files…" 
                    click="this.browseForFiles(event)"
                    />

                <mx:Button id="buttonSelectDir" 
                    label="Add folder…" 
                    click="this.browseForDirectory(event)"
                    />

                <mx:Button id="buttonClearFiles" 
                    label="Remove all" 
                    click="this.removeAllFiles(event)"
                    />

                <mx:Spacer width="100%"/>

                <mx:Button label="Settings…"
                    click="this.viewStack.selectedChild = this.vBoxSettings"
                    />
                            
                <mx:Spacer width="100%"/>

                <mx:Button id="upload_btn" 
                    label="Start upload" 
                    click="this.startUpload(event)"
                    enabled="{this.uploadButtonEnabled(this.upload_url, this.upload_hotfolder)}"
                    />
                
            </mx:HBox>

        </mx:VBox>

        <mx:VBox id="vBoxSettings"
            width="100%" height="100%"
            creationComplete="this.vBoxSettingsCreationComplete()"
            >

            <mx:Form 
                width="100%"
                >
                
                <mx:FormItem
                    label="URL:"
                    width="100%"
                    >
                    
                    <mx:TextInput id="TextInput_Settings_URL"
                         width="100%"
                         text="{this.upload_url}"
                         />
                    
                </mx:FormItem>
                
                <mx:FormItem
                    label="User name:"
                    width="100%"
                    >
                    
                    <mx:TextInput id="TextInput_Settings_Username"
                         width="100%"
                         text="{this.upload_username}"
                         />
                    
                </mx:FormItem>
                
                <mx:FormItem
                    label="Password:"
                    width="100%"
                    >
                    
                    <mx:TextInput id="TextInput_Settings_Password" 
                        displayAsPassword="true"
                        width="100%"
                        text="{this.upload_password}"
                        />
                    
                </mx:FormItem>
                
                <mx:FormItem
                    label="Upload into hotfolder:"
                    width="100%"
                    >
                    
                    <mx:TextInput id="TextInput_Settings_Hotfolder"
                         width="100%"
                         text="{this.upload_hotfolder}"
                         />
                    
                </mx:FormItem>
                
            </mx:Form>

            <mx:VBox
                id="VBox_FieldValues_Container" 
                width="100%" height="100%"
                >
                
                <mx:Text text="Field values to set:"/>
                
                <mx:HBox
                    width="100%">
                    
                    <mx:ComboBox
                        id="ComboBox_FieldValues_1_Field"
                        width="150"
                        editable="false"
                        prompt="Choose field:"
                        dataProvider="{this.tagdefs}"
                        />
                        
                    <mx:TextInput
                        id="TextInput_FieldValues_1_Value"
                        width="100%"
                        text="{this.upload_fv_1_value}"
                        />
                    
                    <mx:ComboBox
                        id="ComboBox_FieldValues_1_Mode"
                        width="150"
                        editable="false"
                        prompt="Choose mode:"
                        dataProvider="{this.tagmodes}"
                        />
                    
                </mx:HBox>
                
                <mx:HBox
                    width="100%">
                    
                    <mx:ComboBox
                        id="ComboBox_FieldValues_2_Field"
                        width="150"
                        editable="false"
                        prompt="Choose field:"
                        dataProvider="{this.tagdefs}"
                        />
                        
                    <mx:TextInput
                        id="TextInput_FieldValues_2_Value"
                        width="100%"
                        text="{this.upload_fv_2_value}"
                        />
                    
                    <mx:ComboBox
                        id="ComboBox_FieldValues_2_Mode"
                        width="150"
                        editable="false"
                        prompt="Choose mode:"
                        dataProvider="{this.tagmodes}"
                        />
                    
                </mx:HBox>
                
                <mx:HBox
                    width="100%">
                    
                    <mx:ComboBox
                        id="ComboBox_FieldValues_3_Field"
                        width="150"
                        editable="false"
                        prompt="Choose field:"
                        dataProvider="{this.tagdefs}"
                        />
                        
                    <mx:TextInput
                        id="TextInput_FieldValues_3_Value"
                        width="100%"
                        text="{this.upload_fv_3_value}"
                        />
                    
                    <mx:ComboBox
                        id="ComboBox_FieldValues_3_Mode"
                        width="150"
                        editable="false"
                        prompt="Choose mode:"
                        dataProvider="{this.tagmodes}"
                        />
                    
                </mx:HBox>
                
            </mx:VBox>    
        
            <mx:HBox 
                width="100%" 
                horizontalAlign="right"
                >
                
                <mx:Button label="Cancel"
                    click="this.cancelSettings()"
                    />
                                    
                <mx:Button label="Save"
                    click="this.saveSettings()"
                    />
            
            </mx:HBox>
        
        </mx:VBox>

    </mx:ViewStack>
            
</mx:WindowedApplication>

