/* class */ function FileUploadController( form, callback ) {
	this.setCompletionCallback( callback );
	this.bindForm( form );
	return;  // or browser will think the document is still open
	}
	
extend( FileUploadController.prototype, {

	_form				:	null
,	getForm				:	function( ) {
		return this._form;
		}
,	setForm				:	function( v ) {
		this._form = v;
		return this;
		}
		
,	_key				:	null
,	getKey				:	function( ) {
		return this._key;
		}
,	setKey				:	function( v ) {
		this._key = v;
		if( this.getAPCNode( ) ) {
			this.getAPCNode( ).value	= v;
			}
		return this;
		}

,	_APCNode							:	null
,	getAPCNode							:	function( ) {
		return this._APCNode;
		}
,	setAPCNode							:	function( v ) {
		this._APCNode = v;
		this._APCNode.value = this.getKey( );
		return this;
		}

,	_frame								:	null
,	getFrame							:	function( ) {
		return this._frame;
		}
,	setFrame							:	function( v ) {
		this._frame = v;
		return this;
		}

,	_litebar    						:	null
,	getLitebar							:	function( ) {
		return this._litebar;
		}
,	setLitebar							:	function( v ) {
		this._litebar = v;
		return this;
		}

,   _available                          :   true
,   isAvailable                         :   function( ) {
        return this._available;
    }
,   setAvailable                        :   function( v ) {
        this._available = v;
        return this;
    }
		
,	_completionCallback					:	null
,	getCompletionCallback				:	function( ) {
		return this._completionCallback;
		}
,	setCompletionCallback				:	function( v ) {
		this._completionCallback = v;
		return this;
		}

,	onSubmitComplete					:	function( ) {
		this.getCompletionCallback( )( );
		this.setKey( 'auto_' +  parseInt( Math.random( ) * 100000 ) );
		}

,   _frameOnloadHandler                 :   null
,   getFrameOnloadHandler               :   function( ) {
        return this._frameOnloadHandler;
        }
,   setFrameOnloadHandler               :   function( v ) {
        this._frameOnloadHandler = v;
        return this;
        }

,   bindFrameOnloadHandler              : function( ) {
        var frame   = this.getFrame( );
        
        attachHandler(
              frame
            ,'onload'
            , chainHandlers(
                  frame.onload
                , this.getFrameOnloadHandler( )
              )
            );
        }

,	bindForm			: 	function( form ) {
		this.setForm( form );
        
        // Ensure the clicked button is sent, and the form has file inputs
        var hasFiles = false;
        for( var i = 0; i < form.elements.length; i++ ) {
            element = form.elements[ i ];
            
            switch( element.type ) {
                case 'submit':
                    element.onclick = chainHandlers(
                          element.onclick
                        , function( ) {
                            // cloning and changing the type choked ie7.
                            field = document.createElement( 'input' );
                            
                            field.id = this.id;
                            field.type = 'hidden';
                            field.name = this.name;
                            field.value = this.value;
                            
                            this.parentNode.appendChild( field );
                          }
                    );
                    break;
                
                case 'file':
                    hasFiles = true;
                    break;
            }
        }
        if( !hasFiles ) {
            this.setAvailable( false );
            return;
        }
        
		var key = 'iframe_' + parseInt( Math.random( ) * 100000 );

		/**
		 *	@browser IE
		 *	Internet Explorer is an amazing piece of software; you can not 
		 *	actually set the `name' or `id' elements of an Iframe
		 *	programatically once it has been created. They'll report their new
		 *	values but the frame will not work correctly. Instead, we use
		 *	some sort of ridiculous createElement() syntax.
		 */
		var iframe;
		if( isIE( ) ) {
			iframe = document.createElement(
				'<iframe name="' + key + '" id="' + key + '">'
				);
			}
		else {
			iframe  	= document.createElement( 'iframe' );
			iframe.name = key;
			iframe.id   = key;
			}

		form.appendChild( iframe );

		this.setFrame( iframe );
		iframe.style.visibility = 'hidden';
		iframe.style.height		= '5px';
		iframe.style.width      = '5px';
		iframe.style.position	= 'absolute';
		iframe.style.left		= '-9000px';
			
		form.onsubmit = chainHandlers(
			 form.onsubmit
			,bind( this, 'submit' )
			);
		
		var apc = null;

		for( var ii = 0; ii < form.elements.length; ii++ ) {
			if( form.elements[ ii ].name == 'APC_UPLOAD_PROGRESS' ) {
				apc = form.elements[ ii ];
				break;
				}
			}

		if( !apc ) {
			apc = document.createElement( 'input' );
				apc.type = 'hidden';
				apc.name = 'APC_UPLOAD_PROGRESS';
			form.insertBefore( apc, form.firstChild );
			}

		this.setAPCNode( apc );
		this.setKey( 'auto_' +  parseInt( Math.random( ) * 100000 ) );
		}
		
,	submit				:	function( ) {
        
        // Ensure the form has files to upload
        var form        = this.getForm( );
        var hasFiles    = false;
        for( var i = 0; i < form.elements.length; i++ ) {
            element = form.elements[ i ];
            if( element.type == 'file'
            &&  element.value
            ) {
                hasFiles = true;
                break;
            }
        }
        if( !hasFiles ) {
            this.setAvailable( false );
            return true;
        }
        
        this.bindFrameOnloadHandler( );
		this.getForm( ).target = this.getFrame( ).name;

		this.setLitebar( new LiteboxProgressBar( ) ).getLitebar( )
			.setUpdateURI( 
				auri( 'vault/monitor/' + encodeURI( this.getKey( ) ) + '/' )
				)
			.setCompletionCallback(
				bind( this, 'onSubmitComplete' )
				)
			.show( )
			;
        
		return true;
		}

	} );


//-( VaultLitebox )-------------------------------------------------------------

/**
 *	Create a modal dialog using an arbitrary node for content.
 *
 *	@class		VaultLitebox
 *	@extends	Litebox
 */
 
/* class */ function VaultLitebox( control ) /* extends Litebox */ {
	Litebox.apply( this, [] );

	this.setCanvas( document.createElement( 'div' ) );
	this.getCanvas( ).className = 'vaultBox';
	this.setIgnoreCanvasClick( true );
	this.show();
	
	this.setBoundControl( control );
	this.getCanvas( ).appendChild( this.buildLiveSearchNode( ) );
	this.getCanvas( ).appendChild( this.buildLiveResultNode( ) );
	this.getCanvas( ).appendChild( this.buildDialogButtons( ) );
	this.getCanvas( ).appendChild( document.createElement( 'hr' ) );
	this.getCanvas( ).appendChild( this.buildFileUploadForm( ) );

	}

extend( VaultLitebox.prototype, Litebox.prototype );
extend( VaultLitebox.prototype, {
 	constructor				: 	LiteboxImage
 	
,	_boundControl			:	null
,	getBoundControl			:	function( ) {
		return this._boundControl;
		}
,	setBoundControl			:	function( v ) {
		this._boundControl = v;
		return this;
		}

,	_proxyControl			:	null
,	getProxyControl			:	function( ) {
		return this._proxyControl;
		}
,	setProxyControl			:	function( v ) {
		this._proxyControl = v;
		return this;
		}

,	_fileUploadControl				:	null
,	getFileUploadControl				:	function( ) {
		return this._fileUploadControl;
		}
,	setFileUploadControl				:	function( v ) {
		this._fileUploadControl = v;
		return this;
		}

,	_searchInput				:	null
,	getSearchInput				:	function( ) {
		return this._searchInput;
		}
,	setSearchInput				:	function( v ) {
		this._searchInput = v;
		return this;
		}

,	_activityImage				:	null
,	getActivityImage				:	function( ) {
		return this._activityImage;
		}
,	setActivityImage				:	function( v ) {
		this._activityImage = v;
		return this;
		}
		
,	setQuerying				:	function( q ) {
		if( q ) {
			this.getActivityImage( ).style.display = '';
			}
		else {
			this.getActivityImage( ).style.display = 'none';
			}
		return this;
		}

		
,	_statusMessage				:	null
,	getStatusMessage				:	function( ) {
		return this._statusMessage;
		}
,	setStatusMessage				:	function( v ) {
		this._statusMessage = v;
		setHTML(
			 this.getStatusMessageNode( )
			,v + '<br />' + this.getAdditionalMessage( )
			);
		return this;
		}
		
,	getAdditionalMessage				: 	function( ) {
		var x = this.getBoundControl( ).getImageWidth( );
		var y = this.getBoundControl( ).getImageHeight( );
		if( x || y ) {
			var msg = 'Image must be ';
			if( x && y ) {
				msg = msg + x + 'px &times; ' + y + 'px.';
				}
			else {
				if( x ) {
					msg = msg + x + 'px wide.';
					}
				else {
					msg = msg + y + 'px high.';
					}
				}
			return msg;
			}
		return '';
		}
		
,	_statusMessageNode					:	null
,	getStatusMessageNode				:	function( ) {
		return this._statusMessageNode;
		}
,	setStatusMessageNode				:	function( v ) {
		this._statusMessageNode = v;
		return this;
		}

 	
,	buildLiveSearchNode		:	function( ) {

		var node = document.createElement( 'table' );
			node.className = 'searchControls';
			var findRow = node.insertRow( 0 );
				var findLabel = findRow.insertCell( 0 );
					findLabel.className = 'label';
					setText( findLabel, 'Find:' );
				var findInput = findRow.insertCell( 1 );
					this.setSearchInput( this.buildSearchInput( ) );
					findInput.appendChild( this.getSearchInput( ) );
				var activityCell = findRow.insertCell( 2 );
					activityCell.rowSpan = 2;
					activityCell.className = 'activity';
					var activityImage = document.createElement( 'img' );
						activityImage.src = 
							auri( 'resource/uicon/status_wait_e3e3e3.gif' );
						this.setActivityImage( activityImage );
						this.setQuerying( false );
						activityCell.appendChild( activityImage );
				var selectionCell = findRow.insertCell( 3 );
					selectionCell.rowSpan = 2;
					selectionCell.className = 'currentImage';
					this.setProxyControl(
						new VaultControl(
							 selectionCell
							,document.createElement( 'input' )
							,this.getBoundControl( ).getAssetID( )
							,this.getBoundControl( ).getDescriptionMarkup( )
							,false
							)
						);
			var statusRow = node.insertRow( 1 );
				var statusLabel = statusRow.insertCell( 0 );
					statusLabel.className = 'label';
					setText( statusLabel, 'Status:' );
				var statusInput = statusRow.insertCell( 1 );
					this.setStatusMessageNode( statusInput );
					this.setStatusMessage( 'No results.' );
			
		return node;

		}
		
,	beginQuery				:	function( ) {
		this.setQuerying( true );
		this.clearSearchResults( );
		this.setStatusMessage( 'Querying...' );
		}

,	buildSearchInput		:	function( ) {
		var searchInput = document.createElement( 'input' );
			searchInput.type		= 'text';
			searchInput._q			= 0;
			searchInput.onchange	= bind( searchInput, 'query' );
			searchInput.onkeydown	= bind( searchInput, 'querySoon' );
			searchInput._box		= this;
			searchInput._oldValue	= true;
		
		searchInput.getQueryCount = function( ) {
			return this._q;
			}

		searchInput.touchQueryCount = function( ) {
			++this._q;
			return this._q;
			};

		searchInput.query = function( ) {
			if( this.value != this._oldValue ) {
				this._oldValue = this.value;
				this._box.beginQuery( );
				this.touchQueryCount( );
				
				var p = [];
				var v = 0;
				if( v = this._box.getBoundControl( ).getImageWidth( ) ) {
					p.push( 'x=' + encodeURI( v ) );
					}
				if( v = this._box.getBoundControl( ).getImageHeight( ) ) {
					p.push( 'y=' + encodeURI( v ) );
					}
				
				if( p ) {
					p = '?' + p.join( '&' );
					}
				else {
					p = '';
					}
					
				LiteBridge.span(
					 auri(
					 	'vault/find/' + encodeURI( this.value ) + '/' + p
					 	)
					,bind( this._box, 'displaySearchResults' )
					);
				}
			};

		searchInput.queryNow = function( arg ) {
			if( arg == this.getQueryCount( ) ) {
				this.query( );
				}
			};

		searchInput.querySoon = function( ) {
			this._box.setStatusMessage( 'Waiting for input...' );
			var q = this.touchQueryCount( );
			var f = bind( this, 'queryNow' );
			setTimeout( bind( null, f, q ), 500 );
			};


		setTimeout( function( ) { searchInput.focus( ); }, 25 );
		
		return searchInput;
		}

,	buildLiveResultNode		:	function( ) {
		
		var t = document.createElement( 'table' );
			t.className = 'searchResults';

	
		var scr = document.createElement( 'div' );
		scr.className = 'scrollPane';
		scr.appendChild( t );
		
		this._litegrid = new LiteGrid( t, this )
			.setSupportsHover( false )
			.setSupportsSelect( false )
			;
			
		return scr;
		}
		
,	buildDialogButtons		: function( ) {
		
		var div = document.createElement( 'div' );
			div.className = 'vaultBoxButtons';
			var submit = document.createElement( 'input' );
				submit.type = 'submit';
				submit.value = 'Save';
				div.appendChild( submit );
				submit.onclick = bind( this, 'save' );
				
			var cancel = document.createElement( 'input' );
				cancel.type = 'submit';
				cancel.value = 'Cancel';
				div.appendChild( cancel );
				cancel.onclick = bind( this, 'cancel' );
				
		return div;
		}
		
,	buildFileUploadForm		: function( ) {
	

		var form = document.createElement( 'form' );
			/**
			 *	@browser ?
			 *	MSDN says `enctype', VisiBone says `encoding'. We might test
			 *	to see which ones actually work; this is pure
			 *	accuracy-by-volume.
			 */
			form.encoding = form.enctype = 'multipart/form-data';
			form.method	= 'post';
			form.action = auri( 'vault/create/' );
			
		var table = document.createElement( 'table' );
			table.className = 'searchControls';
			form.appendChild( table );
			var row = table.insertRow( 0 );
				var label = row.insertCell( 0 );
					label.className = 'label';
					setHTML( label, 'Upload:' );
				var fileCell = row.insertCell( 1 );
					var file = document.createElement( 'input' );
						this.setFileUploadControl( file );
						file.type = 'file';
						file.name = 'vault_file';
						fileCell.appendChild( file );
				var buttonCell = row.insertCell( 2 );
					var btn = document.createElement( 'input' );
						btn.className = 'submit';
						btn.type 	= 'submit';
						btn.value 	= 'Upload File';
						btn._form	= form;
						buttonCell.appendChild( btn );

		form._file = file;
		form.onsubmit = chainHandlers( form.onsubmit, bind( form, function( e ){
			if( !this._file.value ) {
				alert( 'You did not select a file to upload.' );
				return abortEvent( getEvent( e ) );
				}
			return true;
			} ) );
		form._controller = new FileUploadController(
			 form
			,bind( this, 'completeUpload' )
			);
			
		return form;
		}
		
,	completeUpload			: function( ) {
		filename = this.getFileUploadControl( ).value;
		this.getFileUploadControl( ).value = null;
		
		filename = filename.replace( new RegExp( '^.*/|^.*\\\\' ), '' );
		filename = filename.replace( new RegExp( '[^a-zA-Z0-9._-]' ), '' );
		filename = filename.toLowerCase( );

		this.getSearchInput( ).value = filename;
		this.getSearchInput( ).query( );
		}
		
,	clearSearchResults		: function( ) {
		this.setResultSet( null );
		this.getResultControl( ).update( );
		}
		
,	displaySearchResults	: function( results ) {
		this.setQuerying( false );
		if( results.length ) {
			this.setStatusMessage( results.length + ' results.' );
			this.setResultSet( results );
			}
		else {
			this.setStatusMessage( 'No results.' );
			this.setResultSet( null );
			}
		this.getResultControl( ).update( );
		}
		
,	setResultSet			: function( results ) {
		this._resultSet = results;

		if( this._resultSet ) {
			this.getResultControl( ).setSupportsSelect( true );
			}
		else {
			this.getResultControl( ).setSupportsSelect( false );
			}

		return this;
		}
,	getResultSet			: function( ) {
		return this._resultSet;
		}
		
,	getResultControl		: function( ) {
		return this._litegrid;
		}
	
,	getGridRows				: function( ) {
		return	this.getResultSet( )
			?	this.getResultSet( ).length
			:	1;
		}

,	getGridColumns			: function( ) {
		return	this.getResultSet( )
			?	3
			:	1;
		}

,	getGridData				: function( row, col ) {
		if( !this.getResultSet( ) ) {
			return '(No data.)';
			}
		
		row = this.getResultSet( )[ row ];
			
		if( col == 0 ) {
			return '<img src="'
				+ auri( 'resource/vault/' + row[ col ] + '/thumb/64/' )
				+ '" />'
				;
			}
		
		return row[ col ];
		}
		
,	getGridClass			: function( row, col ) {
		if( !this.getResultSet( ) ) {
			return 'mu';
			}
		return [ 'thumb', 'desc', 'info' ][ col ];
		}

,	getResultTable			: function( ) {
		return this._table;
		}
		
,	didGridSelect			: function( grid, state, what, row, evt ) {
		var ctl = this.getProxyControl( );
		var set = this.getResultSet( );		
		ctl.setAssetID( set[ row ][ 0 ] );
		ctl.setDescriptionMarkup( set[ row ][ 1 ] );
		ctl.update( );
		}

,	cancel					: function( ) {
		this.dispose( );
		}
	
,	save					: function( ) {
		bnd = this.getBoundControl( );
		pxy = this.getProxyControl( );
		bnd.setAssetID( pxy.getAssetID( ) );
		bnd.setDescriptionMarkup( pxy.getDescriptionMarkup( ) );
		bnd.update( );
		
		this.dispose( );
		}
		
	} );


