Ext.BLANK_IMAGE_URL = '/funcassociate_client/javascript/ext-3.0.0/resources/images/default/s.gif';

//create namespace
Ext.namespace('Funcassociate');

// constants
Funcassociate.TITLE = 'FuncAssociate 2.0: The Gene Set Functionator';

// avoid timer conflicts
var IN_STATUS_REQUEST_METHOD = false;

// obfuscation in order to avoid at least automated spambots
var maintainer2 = 'beaver';
var maintainer_end = 'hms.harvard.edu'
var maintainer1 = 'john';
var temp = maintainer1 + '_' + maintainer2 + '@' + maintainer_end;

function isNumeric(text) {
	return text.match(/^\d+$|^\d+\.\d+$/ )
}

function isInteger(text) {
	return text.match(/^\d+$/ )
}

Funcassociate.maintainer = '<a href="mailto:' + temp + '">' + temp + '</a>';

// makes up for a deficiency in the vanilla RadioGroup. 
Ext.override(Ext.form.RadioGroup, {
  getName: function() {
    return this.items.first().getName();
  },

  getValue: function() {
    var v;

    this.items.each(function(item) {
      v = item.getRawValue();
      return !item.getValue();
    });

    return v;
  },

  setValue: function(v) {
    this.items.each(function(item) {
      item.setValue(item.getRawValue() == v);
    });
  }
});

// makes a button which extends BoxComponent so that it can be appropriately added to the input panel.
BoxButton = function(config){
    Ext.Button.call(this, config);
};
Ext.apply(BoxButton.prototype, Ext.BoxComponent.prototype);
Ext.apply(BoxButton.prototype, Ext.Button.prototype);
Ext.reg('boxbutton', BoxButton);

Funcassociate.app = function(){
    var DEBUG = false;
    var METHOD = 'method';

    var SERV_URL = '/cgi/funcassociate/serv';
    var DOWNLOAD_ASSOCIATIONS_URL = '/cgi/funcassociate/download_go_associations';
    var DOWNLOAD_RESULTS_URL = '/cgi/funcassociate/download_cached_results';
    var UPLOAD_URL = '/cgi/funcassociate/upload';
    
    var QUERY = 'query';
    var SPECIES = 'species';
    var NAMESPACE = 'namespace';
    var MODE = 'mode';
    var WHICH = 'which';
    var REPS = 'reps';
    var CUTOFF = 'cutoff';
    var QUERY_FILE = 'query-file';
    var ASSOCIATIONS_FILE = 'associations-file';
    var GENESPACE_FILE = 'genespace-file';
    var SUPPORT = 'support';
    
    var ALL_DONE = 'All tasks completed.';
    
    var FUNCASSOCIATE_UPLOAD_PARAMS = [ QUERY_FILE, ASSOCIATIONS_FILE, GENESPACE_FILE ];
    var FUNCASSOCIATE_PARAMS =
      [ QUERY, SPECIES, NAMESPACE, MODE, WHICH, REPS, CUTOFF, SUPPORT ].concat( FUNCASSOCIATE_UPLOAD_PARAMS );
    
    var LIST_BULLET = '<img src="/funcassociate_client/images/arrow.png" height="10px" style="padding-left: 3px; padding-right: 10px"/>';

    var DIE_QUIETLY = 'die-quietly';
    
    var NO_RESULTS_TAB_DESCRIPTOR = {title:'No Results', html: '<div style="padding:5px">No results to Display. Use the sidebar at the left to perform queries.</div>'};
    var EVIDENCE_CODE_DESCRIPTOR = false;
    
    // functionate button-related flags
    var IS_INPUT_READY_FOR_FUNCTIONATE = false;
    var NO_JOB_RUNNING = true;
    var PROGRESS_BAR;
    var SLEEP_INTERVAL = 200;

    var INPUT_PANEL;
    var TABS;
    var EAG_PANEL;
    var EAG;
    var JSON_PANEL;
    var URL_PANEL;
    var PARAMS;

    var $$;
    $$ = {
    	// gather the metadata from the server
        init : function(){
            document.title = Funcassociate.TITLE;
            
            var myMask = new Ext.LoadMask(Ext.getBody(), {msg:"Requesting metadata...", removeMask: true});
        	myMask.show();
        	
        	var transactionId = Ext.Ajax.request({
        		url: SERV_URL,
        		params: {
        			method: 'supported_values'
        		},
        		callback: function(options, success, response) {
        			var metadata = false;
        			if(success) {
        				metadata = Ext.decode(response.responseText);
        			} else {
        				metadata = response.responseText;
        			}
        			myMask.hide();
        			
        			// error handling
        			if(success && metadata && !metadata.error && metadata.result) {
	        			Funcassociate.app.init2(metadata.result, success);
        			} else {
        				Funcassociate.app.report_error(metadata);
        			}
        		}
        	});
        },
        
        report_error: function(metadata, success) {
                Funcassociate.app.reset_progress_bar();
        	if(!metadata) {
        		Ext.Msg.alert('Error', 'An unknown error occurred during the processing of this page. Please contact ' + Funcassociate.maintainer + ' if the problem persists.');
        		return;
        	}
        	
        	if(metadata.error) {
        		Ext.Msg.alert('Error', 'An unknown error (' + metadata.error.code + ') occurred during the processing of this page:<p style="margin:8px;"><code>' + metadata.error.message + '</code></p>Please contact ' + Funcassociate.maintainer + ' if the problem persists.');
        	} else if(metadata.input_error) {
        		Ext.Msg.alert('Error', 'There was an error with your input:<p style="margin:8px;"><code>' + metadata.input_error + '</code></p>Please contact ' + Funcassociate.maintainer + ' if you think this is a mistake.');
        	} else {
        		Ext.Msg.alert('Error', 'An unknown error occurred during the processing of this page. Please contact ' + Funcassociate.maintainer + ' if the problem persists.');
        	}
        },
        
        clear_results_tabs: function() {
        	var downloadButton = Ext.getCmp('download_go_associations_toolbar');
            if(downloadButton) {
           	 downloadButton.destroy();
            }
            downloadButton = Ext.getCmp('download_results_toolbar');
            if(downloadButton) {
           	 downloadButton.destroy();
            }
            
            TABS.removeAll();
        	TABS.add(NO_RESULTS_TAB_DESCRIPTOR);
        	TABS.setActiveTab(0);
        },
        
        // build the interface. This is called by init() after collection of the metadata is finished.
        init2: function(metadataResults, success) {
            var titlePanel = this.createTitlePanel();
            
            var rightPanel = TABS = new Ext.TabPanel({
            	id: 'result_panel',
            	region: 'center',
            	items: [],
            	tbar: ['-']	// force the toolbar to be created even though we have nothing to put into it yet.
            });
            Funcassociate.app.clear_results_tabs();
            
            var leftBar = new Ext.Panel({
            	id: 'left_bar',
            	region: 'west',
            	frame:true,
    	        bodyStyle:'padding:5px 5px 0',
            	width: 440,
            	minWidth: 440,
            	maxWidth: 440,
            	layout: 'fit',
            	split: true,
            	collapsible: true,
            	items: []
            });
            
            Funcassociate.app.createAdvancedInterface(metadataResults);
            
            var centerPanel = new Ext.Panel({
            	layout: 'border',
            	region: 'center',
            	id: 'center_panel',
            	items:[leftBar, rightPanel]
            });
            
            var viewport = new Ext.Viewport({
                layout:'border',
                items:[ centerPanel, titlePanel ]
                });
        },
        
        createTitlePanel: function() {
        	var title = new Ext.Panel({
                x: 5,
                y: 20,
                bodyStyle: {background: 'transparent', border: 'none', color: 'white', font: '25px arial'},
                html: Funcassociate.TITLE
             });
             
        	 var downloadGoAction = this.createMenuItem('DOWNLOAD GO ASSOCIATIONS', '/funcassociate/download_go_associations');
             var documentationAction = this.createMenuItem('DOCUMENTATION', '/funcassociate/documentation');
             var contactAction = this.createMenuItem('CONTACT US', '/funcassociate/contacts');
             var rothAction = this.createMenuItem('ROTH LAB', '/');
             var harvardAction = this.createMenuItem('<img src="/funcassociate_client/images/hms_logo.gif" style="height: 15px"/>', 'http://hms.harvard.edu/');
             
			 var menuBar = new Ext.Toolbar({
			    height: 25,
			    style: 'background-color: black; background-image: none; color: white;'
			 });
            
        	 var titlePanel = new Ext.Panel({
                layout: 'absolute',
                items: [title],
                bodyStyle: {background: 'url(/funcassociate_client/images/roth_header_repeated_center.png) repeat-x'},
                html: '<img src="/funcassociate_client/images/roth_header_left.png" alt="" style="float: left"/><img src="/funcassociate_client/images/roth_header_right.png" alt="" style="float: right"/>',
                height: 73,
                region: 'north',
                bbar: menuBar
             });
            
             // due to ideosyncracies with the menu bar, the menu buttons need to be added after the first render
             titlePanel.on('render', function() { 
            	titlePanel.getBottomToolbar().add(downloadGoAction, contactAction, documentationAction); 
            	titlePanel.getBottomToolbar().addFill();
            	titlePanel.getBottomToolbar().add(rothAction, harvardAction); 
             });

             return titlePanel;
        },
        
        createMenuItem: function(title, url, id) {
        	var config = {
    		        text: '<div style="color: white;">' + title + '</div>',
    		        handler: function() {
			        	window.location = url;
			        }
    		    }; 
        	if(id) {
        		config['id'] = id;
        	}
        	
        	var button = new Ext.Button(config);
		    
		    return button;
        },
        
        createAdvancedInterface: function(metadataResults) {
        	var cutoffValues = metadataResults.cutoff;
        	var modeValues = metadataResults.mode;
        	var namespaceValues = metadataResults.namespaces;
        	var repsValues = metadataResults.reps;
        	var speciesValues = metadataResults.species;
        	var whichValues = metadataResults.which;
        	var sampleInputs = metadataResults.sample_inputs;
        	var evidenceCodes = metadataResults.evidence_codes;
        	
        	if(!DEBUG) {
        		cutoffValues[2] = .99;	// for the sake of client-side response time, we limit P Value cutoffs to .99 and below.
        	}
        	
        	// set up some of the defaults
        	var modeItems = Array(modeValues.length);
        	for(var i = 0; i < modeValues.length; i++) {
        		modeItems[i] = {boxLabel: modeValues[i], id: modeValues[i], checked: false, name: MODE, inputValue: modeValues[i]};
        	}
        	modeItems[0].checked = true;	// default to the first item.
        	
        	var whichItems = Array(whichValues.length);
        	for(var i = 0; i < whichValues.length; i++) {
        		whichItems[i] = {boxLabel: whichValues[i], id: whichValues[i], checked: false, name: WHICH, inputValue: whichValues[i]};
        	}
        	whichItems[0].checked = true;	// default to the first item.
        	
        	var supportItems = Array(evidenceCodes.length);
        	for(var i = 0; i < evidenceCodes.length; i++) {
        		var code = evidenceCodes[i][0];
        		var isInitiallyChecked = evidenceCodes[i][1];
        		supportItems[i] = {boxLabel: code, id: code, checked: isInitiallyChecked, name: SUPPORT, inputValue: code};
        	}
        	
            var speciesData = Array(speciesValues.length);
            for(var i = 0; i < speciesValues.length; i++) {
            	speciesData[i] = [speciesValues[i], ''];
            }
            
            var speciesStore = new Ext.data.SimpleStore({
                fields: ['organism', 'other'],
                data : speciesData
            });
            
            var NamespaceRecord = Ext.data.Record.create([
                                                   {name: 'namespace', mapping: 1}, 
                                                   {name: 'example', mapping: 2},
                                                   {name: 'was_no_translation', mapping: 3},
                                                   {name: 'coverage', mapping: 4}
                                               ]);
            var namespaceStore = new Ext.data.Store({
            	reader: new Ext.data.ArrayReader({
            	}, NamespaceRecord),
                data : Array(0)
            });
        	
//        	var interfaceToggle = Ext.getCmp('interface_toggle');
//        	interfaceToggle.setText('<div style="color: white;">GO TO SIMPLE INTERFACE</div>');
        	
//        	interfaceToggle.setHandler(function() {
//	        	Funcassociate.app.createSimpleInterface(metadataResults);
//            });
        	
        	var leftBar = Ext.getCmp('left_bar');
        	leftBar.removeAll(true);	//*** Does this cause memory leaks?
        	
        	EVIDENCE_CODE_DESCRIPTOR = {
                    fieldLabel: 'Evidence Codes',
                    name: SUPPORT,
                    id: SUPPORT,
                    xtype: 'checkboxgroup',
                    columns: 3,
                    items: supportItems
                };
        	
        	var inputPanel = INPUT_PANEL = new Ext.FormPanel({
    	        autoScroll: true,
    	        labelWidth: 100,
    	        id: 'input_panel',
    	        fileUpload: true,
    	        items: [{
    	        	xtype:'fieldset',
    	            title: 'Required Parameters',
    	            collapsible: true,
    	            autoHeight:true,
    	            defaults: {anchor: '100%'},
    	            id: 'input_fieldset',
    	            items :[new Ext.Panel({
    	            	html: LIST_BULLET + '<b>Step 1: Provide either a species or an associations file</b>',
    	            	border: false,
    	            	cls: 'x-form-item custom-label'
    	            }),{
	    	            tpl: '<tpl for="."><div ext:qtip="{organism}: {other}" class="x-combo-list-item">{organism}</div></tpl>',
	    	            store: speciesStore,
	    	            displayField:'organism',
    	                typeAhead: true,
    	                forceSelection: true,
    	                mode: 'local',
    	                triggerAction: 'all',
    	                emptyText:'Select a species...',
    	                selectOnFocus:true,
    	                xtype: 'combo',
    	                name: SPECIES,
    	                id: SPECIES,
    	                fieldLabel: 'Species',
    	                listeners: {
    	            		'select': function(field, newValue, oldValue) {
    	            			Funcassociate.app.speciesChangedAdvanced(newValue.data.organism ? false : true, newValue.data.organism, namespaceValues, namespaceStore);
    	            		}
    	            	}
    	            },new Ext.Panel({
    	            	html: '<b>-- or --</b>',
    	            	border: false,
    	            	cls: 'x-form-item custom-label'
    	            }),{
    	            	name: ASSOCIATIONS_FILE,
    	            	id: ASSOCIATIONS_FILE,
    	            	fieldLabel: 'Associations File',
    	            	xtype: 'fileuploadfield',
    	                emptyText: 'Select a file...',
	                    listeners: {
    	            		'valid': function(field) {
    	            			Funcassociate.app.associationsFileChangedAdvanced(field.getValue() ? false : true);
    	            		}
    	            	}
    	            }]
    	        },{
    	            xtype:'fieldset',
    	            title: 'Optional Parameters (click arrow to expand)',
    	            collapsible: true,
    	            collapsed: true,
    	            autoHeight:true,
    	            labelWidth: 100,
    	            defaults: {anchor: '100%'},
    	            id: 'optional_fieldset',
    	            items :[{
    	                    fieldLabel: 'Mode',
    	                    name: MODE,
    	                    id: MODE,
    	                    xtype: 'radiogroup',
    	                    columns: 1,
    	                    items: modeItems
    	                },{
    	                    fieldLabel: 'Over/Under',
    	                    name: WHICH,
    	                    id: WHICH,
    	                    xtype: 'radiogroup',
    	                    columns: 1,
    	                    items: whichItems
    	                },{
    	                    fieldLabel: 'Simulations',
    	                    name: REPS,
    	                    id: REPS,
    	                    xtype: 'textfield',
    	                    value: repsValues[0],
    	                    validator: function(text) {
    	                		return isInteger(text) && text >= repsValues[1] && text <= repsValues[2] && Ext.getCmp(CUTOFF).getValue() >= (1 / text);
    	                	},
    	                    width: 50
    	                },{
    	                    fieldLabel: 'P-Value Cutoff',
    	                    name: CUTOFF,
    	                    id: CUTOFF,
    	                    xtype: 'textfield',
    	                    validator: function(text) {
    	                		return isNumeric(text) && text >= cutoffValues[1] && text <= cutoffValues[2] && text >= (1 / Ext.getCmp(REPS).getValue());
    	                	},
    	                    value: cutoffValues[0],
    	                    width: 50
    	                }
    	            ]
    	        },
    	        {
    	        	xtype: 'panel',
    	        	layout: 'fit',
    	        	id: 'buttonPanel',
    	        	width: 290,
    	        	
    	        	buttons: [{
        	            text: 'Functionate!',
        	            id: 'functionate_button',
        	            disabled: true,
        	            handler: function(){
	                    	var input_fields = FUNCASSOCIATE_UPLOAD_PARAMS;

	                    	var optionalFieldset = Ext.getCmp('optional_fieldset');
	                        var wasOptionalFieldsetVisible = !optionalFieldset.collapsed;
	                        if(!wasOptionalFieldsetVisible) {
	                        	optionalFieldset.expand();
	                        }
	                    	
	                    	var dieQuietly = Ext.getCmp( DIE_QUIETLY );
	                    	var have_uploads = dieQuietly && dieQuietly.getValue();
                         
	                    	for ( var i = 0, len = input_fields.length; i < len && !have_uploads; ++i ) {
	                    		var field = input_fields[ i ];
	                    		var fieldCmp = Ext.getCmp( field );
	                    		if(fieldCmp) {
    	                    		var v = fieldCmp.getValue();
    	                    		have_uploads = !! v.match( /\S/ );
	                    		}
	                    	}

                            PROGRESS_BAR.updateText( 'initializing...' );

                            Funcassociate.app.clear_results_tabs();
                            
                            if(wasOptionalFieldsetVisible) {
                            	optionalFieldset.collapse();
                            }
                            
	                    	if ( have_uploads ) {
	                    		Ext.getDom('file_submit_frame').flag = true;  // flag to process_iframe_results() to make sure that it ignores the first display

	                    		var domForm = inputPanel.getForm().getEl().dom;
	                    		domForm.target = 'file_submit_frame';
	                    		domForm.action = UPLOAD_URL;
	                    		domForm.submit();
	                    	}
	                    	else {
	                    		// no files were specified, so just move directly to the ajax call.
	                    		Funcassociate.app.process_and_functionate('No files were specified');
	                    	}
    	                }
        	        },{
        	            text: 'Load Sample Inputs',
        	            handler: function(){
        	        		// expand the optional fieldset so that its elements are visible to Ext
        	        		Ext.getCmp('optional_fieldset').expand();
        	        	
        	        		Ext.getCmp(ASSOCIATIONS_FILE).setValue('');
        	        		Funcassociate.app.associationsFileChangedAdvanced(true);
        	        	
        	        		var species = sampleInputs['species'];
    	    	        	Ext.getCmp(SPECIES).setValue(species);
    	    	        	Funcassociate.app.speciesChangedAdvanced(false, species, namespaceValues, namespaceStore);
    	    	        	
    	    	        	Ext.getCmp(NAMESPACE).setValue(sampleInputs['namespace']);
    	            		Ext.getCmp(NAMESPACE).setDisabled(false);
    	            		Funcassociate.app.namespaceChangedAdvanced(false);
    	    	        	
    	            		Ext.getCmp(QUERY).setValue(sampleInputs['query']);
    	            		Ext.getCmp(QUERY_FILE).setValue('');
    	            		
    	            		Ext.getCmp('unordered').setValue(true);
    	            		Ext.getCmp('ordered').setValue(false);
    	            		Ext.getCmp('over').setValue(true);
    	            		Ext.getCmp('under').setValue(false);
    	            		Ext.getCmp('both').setValue(false);
    	            		Ext.getCmp(CUTOFF).setValue(cutoffValues[0]);
    	            		Ext.getCmp(REPS).setValue(repsValues[0]);
    	            		
    	                	for(var i = 0; i < evidenceCodes.length; i++) {
    	                		var code = evidenceCodes[i][0];
    	                		var isInitiallyChecked = evidenceCodes[i][1];
    	                		Ext.getCmp(code).setValue(isInitiallyChecked);
    	                	}
    	                	
    	                	Ext.getCmp('optional_fieldset').collapse();
        	        	}
        	        }]
    	        },
                PROGRESS_BAR = new Ext.ProgressBar({
                	region: 'south',
                	id: 'progress_bar',
                	text: '',
                	height: 20,
                	listeners: {
                		'update': function(bar, value, text) {
                                  var t = bar.text;
                                  NO_JOB_RUNNING = ( t == '' || t == ALL_DONE );
                                  Funcassociate.app.activateFunctionateButtonMaybe();
                		}
                	}
                })]
            });
        	
    		leftBar.add(inputPanel);
    		leftBar.doLayout();
        },
        
        speciesChangedAdvanced: function(isEmpty, newSpecies, namespaceValues, namespaceStore) {
        	var fieldSet = Ext.getCmp('input_fieldset');
        	
        	var namespace = Ext.getCmp(NAMESPACE);
    		if(namespace) {
    			fieldSet.remove(namespace, true);
    			Ext.destroy(namespace.container.up('.x-form-item'));
    		}
        	
        	if(isEmpty) {
        		var step2Label = Ext.getCmp('step_2_label');
        		if(step2Label) {
        			fieldSet.remove(step2Label, true);
        			Ext.destroy(step2Label.container.up('.x-form-item'));
        		}
        		
        		Funcassociate.app.namespaceChangedAdvanced(true);
        	} else {
        		Ext.getCmp(ASSOCIATIONS_FILE).setValue('');
        		Funcassociate.app.associationsFileChangedAdvanced(true);
        		
        		// only add the components if they don't already exist
        		if(!Ext.getCmp('step_2_label')) {
	        		fieldSet.add(new Ext.Panel({
		            	html: LIST_BULLET + '<b>Step 2: Choose a namespace</b>',
		            	border: false,
		            	id: 'step_2_label',
		            	cls: 'x-form-item custom-label'
		            }));
	        		
	        		fieldSet.add({
	    	            tpl: '<tpl for="."><tpl if="was_no_translation"><div class="x-combo-list-item"><b ext:qtip="{namespace}<tpl if="example"> (Example: {example}, No Translation)</tpl>">{namespace}<tpl if="example">  (Example: {example}, No Translation)</tpl></b></div></tpl><tpl if="!was_no_translation"><div ext:qtip="{namespace}<tpl if="example"> (Example: {example}, Coverage: {coverage}%)</tpl>" class="x-combo-list-item">{namespace}<tpl if="example">  (Example: {example}, Coverage: {coverage}%)</tpl></div></tpl></tpl>',
	    	            store: namespaceStore,
	    	            displayField:'namespace',
		                typeAhead: true,
		                forceSelection: true,
		                mode: 'local',
		                triggerAction: 'all',
		                emptyText:'Select a namespace...',
		                selectOnFocus:true,
		                xtype: 'combo',
		                name: NAMESPACE,
		                id: NAMESPACE,
		                fieldLabel: 'Namespace',
		                listeners: {
		            		'select': function(field, newValue, oldValue) {
	            				Funcassociate.app.namespaceChangedAdvanced(newValue.data.namespace ? false : true);
		            		},
		            		'beforequery': function(qe){
		                        delete qe.combo.lastQuery;
		                    }
	            		}
		            });
	        		fieldSet.doLayout();
        		}
        		
        		var comboBox = Ext.getCmp(NAMESPACE);
				comboBox.setValue('');
				
				var values = namespaceValues[newSpecies];
				var data = Array(values.length);
				for(var i = 0; i < values.length; i++) {
					var value = values[i];
					data[i] = [i, value[0], value[1], value[2], value[3]];
				}
				
				comboBox.store.loadData(data, false);
				
				// if there is only one available namespace, select it
				if(values.length == 1) {
					comboBox.setValue(values[0][0]);
					Funcassociate.app.namespaceChangedAdvanced(false);
				} else {
					Funcassociate.app.namespaceChangedAdvanced(true);
				}
        	}
        },
        
        addQueryFieldsAdvanced: function(stepNumber) {
        	var fieldSet = Ext.getCmp('input_fieldset');
        	
        	// only add the components if they don't already exist
    		if(!Ext.getCmp(QUERY)) {
    			fieldSet.add(new Ext.Panel({
	            	html: LIST_BULLET + '<b>Step ' + stepNumber + ': Provide a list of genes as a query</b>',
	            	border: false,
	            	id: 'step_' + stepNumber + '_label',
	            	cls: 'x-form-item custom-label'
	            }));
    			
    			fieldSet.add({
                    name: QUERY,
                    id: QUERY,
                    emptyText:'Paste a list of genes here or provide a file below...',
                    xtype: 'textarea',
                    fieldLabel: 'Query List',
                    height: 100,
                    listeners: {
	            		'valid': function(field) {
	            			Funcassociate.app.queryChangedAdvanced(field.getValue() ? false : true);
	            		}
	            	}
	            });
    			
    			fieldSet.add({
	            	name: QUERY_FILE,
	            	id: QUERY_FILE,
	            	fieldLabel: 'Query File',
	            	xtype: 'fileuploadfield',
	            	emptyText: 'Select a file...',
	            	listeners: {
	            		'valid': function(field) {
	            			Funcassociate.app.queryFileChangedAdvanced(field.getValue() ? false : true);
	            		}
	            	}
	            });
    			
    			fieldSet.doLayout();
    		}
    		
    		IS_INPUT_READY_FOR_FUNCTIONATE = true;
    		Funcassociate.app.activateFunctionateButtonMaybe();
        },
        
        removeQueryFieldsAdvanced: function(stepNumber) {
        	var fieldSet = Ext.getCmp('input_fieldset');
        	
    		var query = Ext.getCmp(QUERY);
    		if(query) {
    			fieldSet.remove(query, true);
    			Ext.destroy(query.container.up('.x-form-item'));
    		}
    		
    		var queryFile = Ext.getCmp(QUERY_FILE);
    		if(queryFile) {
    			fieldSet.remove(queryFile, true);
    			Ext.destroy(queryFile.container.up('.x-form-item'));
    		}
    		
    		var step = Ext.getCmp('step_' + stepNumber + '_label');
    		if(step) {
    			fieldSet.remove(step, true);
    			Ext.destroy(step.container.up('.x-form-item'));
    		}
    		
    		IS_INPUT_READY_FOR_FUNCTIONATE = false;
    		Funcassociate.app.activateFunctionateButtonMaybe();
        },
        
        associationsFileChangedAdvanced: function(isEmpty) {
        	var fieldSet = Ext.getCmp('input_fieldset');
        	
			if(isEmpty) {
				Funcassociate.app.removeQueryFieldsAdvanced(2);
			} else {
				Ext.getCmp(SPECIES).setValue('');
				Funcassociate.app.speciesChangedAdvanced(true);
				
				Funcassociate.app.addQueryFieldsAdvanced(2);
			}
        },
        
        namespaceChangedAdvanced: function(isEmpty) {
        	var fieldSet = Ext.getCmp('input_fieldset');
        	var optionalSet = Ext.getCmp('optional_fieldset');

        	Funcassociate.app.removeQueryFieldsAdvanced(3);
        	
        	if(isEmpty) {
        		var geneSpaceFile = Ext.getCmp(GENESPACE_FILE);
        		if(geneSpaceFile) {
        			fieldSet.remove(geneSpaceFile, true);
        			Ext.destroy(geneSpaceFile.container.up('.x-form-item'));
        		}
        		
        		var support = Ext.getCmp(SUPPORT);
        		if(support) {
        			fieldSet.remove(support, true);
        			Ext.destroy(support.container.up('.x-form-item'));
        		}
        	} else {
        		Funcassociate.app.addQueryFieldsAdvanced(3);
        		
        		// only add the components if they don't already exist
        		if(!Ext.getCmp(GENESPACE_FILE)) {
        			optionalSet.add(EVIDENCE_CODE_DESCRIPTOR);
        			
        			optionalSet.add({
	                    fieldLabel: 'Gene Space File',
	                    name: GENESPACE_FILE,
	                    id: GENESPACE_FILE,
	                    xtype: 'fileuploadfield',
	                    emptyText: 'Select a file...',
	                    listeners: {
    	            		'valid': function(field) {
    	            			Funcassociate.app.geneSpaceFileChangedAdvanced(field.getValue() ? false : true);
    	            		}
    	            	}
	                });
	        		
        			optionalSet.doLayout();
        		}
        	}
        },
        
        geneSpaceFileChangedAdvanced: function(isEmpty) {
        	
        },
        
        queryChangedAdvanced: function(isEmpty) {
        	if(!isEmpty) {
        		Ext.getCmp(QUERY_FILE).setValue('');
        	}
        },
        
        queryFileChangedAdvanced: function(isEmpty) {
        	if(!isEmpty) {
        		Ext.getCmp(QUERY).setValue('');
        	}
        },
        
        activateFunctionateButtonMaybe: function() {
        	var button = Ext.getCmp('functionate_button');
        	var backButton = Ext.getCmp('move-prev-options')
        	if(button) {
	        	if(NO_JOB_RUNNING && IS_INPUT_READY_FOR_FUNCTIONATE) {
	        		button.enable();
	        		if(backButton) {
	        			backButton.enable();
	        		}
	        	} else {
	        		button.disable();
	        		if(backButton) {
	        			backButton.disable();
	        		}
	        	}
        	}
        },
        
        process_iframe_results: function ( frame ) {
            // see above. Causes this code to ignore the iframe's initial load.
            if ( !frame.flag ) return;

            var error_message;
            var upload_response

            var pre = Ext.getDom('file_submit_frame').contentDocument.body.innerHTML;
            var content = pre.replace( /^<pre>/i, '' ).replace( /<\/pre>/i, '' );

            if ( content == '' || content.match( /\b500\b/ ) && content.match( /\berror\b/i ) ) {
            	if ( DEBUG ) {
            		error_message = content || 'no content';
            	}
            	else {
            		error_message = '500 Internal Server Error';
            	}
            }
            else {
            	upload_response = Ext.decode( content );
            	var error;
            	if ( error = upload_response.error ) {
            		if ( DEBUG ) {
            			error_message = error.message || 'Internal Server Error';
            		}
            		else {
            			error_message = 'Internal Server Error';
            		}
            	}
            }

            if ( error_message ) {
            	Ext.Msg.alert( 'Error', error_message );
                Funcassociate.app.reset_progress_bar();
            	return;
            }

            Funcassociate.app.process_and_functionate( upload_response.result );
        },

        reset_progress_bar: function () {
        	if(PROGRESS_BAR) {
        		PROGRESS_BAR.updateProgress( 0, ALL_DONE, false );
        		PROGRESS_BAR.reset();
        	}
        },
          
        process_and_functionate: function( cache_keys ) {
            var input_fields = FUNCASSOCIATE_PARAMS;
            //var params = { method: 'fake_functionate_submit' };
            var params = { method: 'functionate_submit' };
            var upload_errors = [];
            
            var optionalFieldset = Ext.getCmp('optional_fieldset');
            var wasOptionalFieldsetVisible = !optionalFieldset.collapsed;
            if(!wasOptionalFieldsetVisible) {
            	optionalFieldset.expand();
            }

            for ( var i = 0, len = input_fields.length; i < len; ++i ) {
            	var field = input_fields[ i ];
            	var v;
            	
            	var f = Ext.getCmp( field );
            	
            	if ( f == null ) continue;
            	
            	// need to handle the support field specially. All other fields have a unique value, but this is a checkbox group.
            	if(field == SUPPORT) {
            		v = new Array();
            		for(var j in f.items.items) {
            			var item = f.items.items[j];
            			if(item.getValue && item.getValue()) {
            				v.push(item.getId()) 
            			}
            		}
            	} else {
	            	v = f.getValue();
            	}
            	
            	if ( field.match( /-file$/ ) ) {
            		if ( v.match( /\S/ ) ) {
	                  // we have a non-all-whitespace value for this field; in
	                  // this case, we will initialize files[ field ] to the
	                  // corresponding key from the value returned by the
	                  // upload script
	                  var key;
	                  if ( cache_keys ) params[ 'cached-' + field ] = key = cache_keys[ field ];
	
	                  // key will be false in either of two cases: nothing was
	                  // returned by the upload script, or the script returned
	                  // an object in which a false value was assigned to this
	                  // field, meaning that the script failed to upload this
	                  // one file; in either case, we add the filename entered
	                  // by the user in this field to the upload_errors array
	                  if ( !key ) upload_errors.push( v );
            		}
            		else {
            			params[ field ] = null;
            		}
            	}
            	else {
            		params[ field ] = v;
            	}
            }

            if ( upload_errors.length ) {
            	var msg = 'unable to upload the following file(s): ' + upload_errors.join( ', ' );
                // display upload 
            	Ext.Msg.alert( 'Error', msg );
            	return;
            }

            PARAMS = params;
            
            if(wasOptionalFieldsetVisible) {
            	optionalFieldset.collapse();
            }

            Ext.Ajax.request({
            	url: SERV_URL,
            	params: params,
            	callback: function(options, success, response) {
            		var processedResult = false;
            		if(success) {
                          START = Funcassociate.app.now();
                          processedResult = Ext.decode(response.responseText);
            		} else {
                          processedResult = response.responseText;
            		}
            		
            		// error handling
            		if(success && processedResult && !processedResult.error && processedResult.result) {
                          Funcassociate.app.functionate_status_request( processedResult.result );
            		} else {
                          Funcassociate.app.report_error(processedResult);
            		}
            } } );
        },

        functionate_status_request: function ( job_id ) {
           Ext.Ajax.request({
           url: SERV_URL,
           params: { method: 'status', 'job-id': job_id},
           callback: function(options, success, response) {
             var processedResult = false;
             if(success) {
               processedResult = Ext.decode(response.responseText);
             } else {
               processedResult = response.responseText;
             }
                   // error handling
             if(success && processedResult && !processedResult.error && processedResult.result) {
                     // success. Now, did the method tell us that the process is finished, or did it tell us the progress?
                     if(processedResult.result[0]) {
                             var result = processedResult.result[1];
                             if(result.input_error) {
                                     Funcassociate.app.report_error(result);
                             } else {
                            	 	TABS.removeAll();
                            	 	TABS.getTopToolbar().removeAll();
                                     var grid_panels = Funcassociate.app.make_result_panels( result );
                                     if(!grid_panels) {
                                    	 Funcassociate.app.clear_results_tabs();
                                         Funcassociate.app.reset_progress_bar();
                                    	 return;
                                     }

                                     var which = [ 'over', 'under' ];
                                     var active_id;
                                     for ( var i = 0; i < 2; ++i ) {
                                       var w = which[ i ];
                                       var grid = grid_panels[ w ];
                                       if ( !grid ) continue;
                                       TABS.add( grid );
                                       if ( typeof active_id === 'undefined' ) active_id = grid.id;
                                     }

                                     TABS.setActiveTab( active_id );
                                     TABS.add( Funcassociate.app.make_info_panel( result ) );
                                     var warnings_panel = Funcassociate.app.make_warnings_panel( result );
                                     if ( warnings_panel )
                                       TABS.add( Funcassociate.app.make_warnings_panel( result ) );

                                     // add the download buttons...
                                     
                                     if(Ext.getCmp(GENESPACE_FILE)) {	// use the genespace file field as a flag for whether this should be added here.
	                                     TABS.getTopToolbar().addButton({
	                                    	 text: 'Download GO Associations',
	                                    	 id: 'download_go_associations_toolbar',
	                                    	 handler: function() {
	                                    	 	var downloadForm = Ext.getDom('download_data_by_job_id_form');
	                                    	 
		     			            			Ext.getDom('download_data_job_id').value = job_id;
		     			            			downloadForm.action = DOWNLOAD_ASSOCIATIONS_URL;
		     			            			downloadForm.submit();
		     			            			return false;
	                                     	 }
	                                     });
                                     }
                                     TABS.getTopToolbar().addButton({
                                    	 text: 'Download Results',
                                    	 id: 'download_results_toolbar',
                                    	 handler: function() {
                                    	 	var downloadForm = Ext.getDom('download_data_by_job_id_form');
                                    	 
	     			            			Ext.getDom('download_data_job_id').value = job_id;
	     			            			downloadForm.action = DOWNLOAD_RESULTS_URL;
	     			            			downloadForm.submit();
	     			            			return false;
                                     	 }
                                     });
                                     
                                     Funcassociate.app.create_entity_attributes_grid(job_id);
                                     PROGRESS_BAR.updateProgress(1, '100%', true);
                             }
                     }
                     else if ( processedResult.result.length > 1 ) {
                       var progress = processedResult.result[ 1 ];
                       PROGRESS_BAR.updateProgress( progress/100, progress + '%', true );
                       if ( SLEEP_INTERVAL > 0 ) {
                         var callback = function () { Funcassociate.app.functionate_status_request( job_id ) };
                         setTimeout( callback, SLEEP_INTERVAL );
                       }
                       else {
                         Funcassociate.app.functionate_status_request( job_id );
                       }
                     }
                     else {
                       Ext.Msg.alert( 'Error', 'internal error' );
                     }
             } else {
               Funcassociate.app.report_error(processedResult);
             }
          } } );
        },
        
        create_entity_attributes_grid: function(job_id) {
            PROGRESS_BAR.updateText('Retrieving entity attribute table...');
                
        	Ext.Ajax.request({
            	url: SERV_URL,
            	params: { method: 'entity_attribute_table', 'job-id': job_id},
            	callback: function(options, success, response) {
                      var processedResult = false;
                      var times = new Array();
                      times.push( Funcassociate.app.now() );
                      if (success) {
                        processedResult = Ext.decode(response.responseText);
                      } else {
                        processedResult = response.responseText;
                      }
                      times.push( Funcassociate.app.now() ); // elapsed 69
                      
                      if ( !(success && processedResult && !processedResult.error && processedResult.result) ) {
                        Funcassociate.app.report_error(processedResult);
                        return;
                      }

                      var result = processedResult.result;
                      
                      TABS.remove( EAG, true );
                      EAG = Funcassociate.app.make_eat_panel( result, 50 );
                      TABS.add( EAG );
                      TABS.setActiveTab(0);    // otherwise, the entity attribute tab becomes active.
                      
                      Funcassociate.app.reset_progress_bar();
                    }
        	  });
              PROGRESS_BAR.updateProgress(1, '100%', true);
              Funcassociate.app.reset_progress_bar();
      },

      now: function () {
        return ( new Date() ).getTime();
      },

      load_json: function ( data ) {
        TABS.remove( JSON_PANEL, true );
        JSON_PANEL = Funcassociate.app.make_json_panel( JSON.stringify( data ) );
        TABS.add( JSON_PANEL );
        TABS.setActiveTab( JSON_PANEL.id );
      },

      load_url_encoded_params: function ( params ) {
        TABS.remove( URL_PANEL, true );
        URL_PANEL = Funcassociate.app.make_url_panel( Ext.urlEncode( params ) );
        TABS.add( URL_PANEL );
        TABS.setActiveTab( URL_PANEL.id );
      }
    };

  return $$;
}();

Ext.QuickTips.init();

// cause the tooltip to wait 100 seconds before autohiding (unless the user moves the mouse)
Ext.onReady(function(){
   Ext.apply(Ext.QuickTips.getQuickTip(), {
       dismissDelay: 100000
   });
});

Ext.onReady(Funcassociate.app.init, Funcassociate.app);
