Ext.onReady(init);

var active_tab = null;

//The components of the query
var list = new lightweight_list();

//Initialize the application
function init() {
			
	//Setup the tabs
	var tab1 = Ext.get('tab1');
	var tab2 = Ext.get('tab2');
	var tab3 = Ext.get('tab3');
	var tab4 = Ext.get('tab4');
	
	tab1.on('mousedown', select_tab); //search
	tab2.on('mousedown', select_tab); //results
	tab3.on('mousedown', select_tab); //about
	tab4.on('mousedown', select_tab); //help

	tab1.image = Ext.get('image1');
	tab2.image = Ext.get('image2');
	tab3.image = Ext.get('image3');
	tab4.image = Ext.get('image4');

	tab1.section = Ext.get('section1');
	tab2.section = Ext.get('section2');
	tab3.section = Ext.get('section3');
	tab4.section = Ext.get('section4');
	
	active_tab = tab1;
	tab2.section.setDisplayed(false);
	tab3.section.setDisplayed(false);
	tab4.section.setDisplayed(false);

	//Initialize the data grid
	var grid = new suba_grid({
		url : 'handler.php',
		db : 'suba',
		table : 'suba2',
		pagesize : 50,
		renderTo : 'section2',
		height:540,
		width:1000,
		callback:function() {
			show_tab(tab2)
		}
	});	
	
	//Grab references to the buttons in the button bar
	var f_open   = Ext.get('f_open');
	var f_close  = Ext.get('f_close');
	var f_and    = Ext.get('f_and');
	var f_or     = Ext.get('f_or');
	var f_undo   = Ext.get('f_undo');
	var f_reset  = Ext.get('f_reset');
	var f_submit = Ext.get('f_submit');
	
	//Grab references to the add buttons
	var f_assay_add = Ext.get('f_assay_add');
	var f_pred_add  = Ext.get('f_pred_add');
	var f_ref_add   = Ext.get('f_ref_add');
	var f_info_add  = Ext.get('f_info_add');
	var f_num_add   = Ext.get('f_num_add');
	var f_chr_add   = Ext.get('f_chr_add');
	var f_agi_add   = Ext.get('f_agi_add');
	
	//Grab reference to the info buttons
	var f_assay_info = Ext.get('f_assay_info');
	var f_pred_info  = Ext.get('f_pred_info');
	var f_ref_info   = Ext.get('f_ref_info');
	var f_info_info  = Ext.get('f_info_info');
	var f_num_info   = Ext.get('f_num_info');
	var f_chr_info   = Ext.get('f_chr_info');
	var f_agi_info   = Ext.get('f_agi_info');
		
	//Grab references to all other form components
	var f_render = Ext.get('f_render');

	var f_assay_col = Ext.get('f_assay_col');
	var f_pred_col  = Ext.get('f_pred_col');
	var f_ref_col   = Ext.get('f_ref_col');
	var f_info_col  = Ext.get('f_info_col');
	var f_num_col   = Ext.get('f_num_col');
	var f_chr_col   = Ext.get('f_chr_col');
	var f_agi_col   = Ext.get('f_agi_col');

	var f_assay_op = Ext.get('f_assay_op');
	var f_pred_op  = Ext.get('f_pred_op');
	var f_ref_op   = Ext.get('f_ref_op');
	var f_info_op  = Ext.get('f_info_op');
	var f_num_op   = Ext.get('f_num_op');
	var f_chr_op   = Ext.get('f_chr_op');
	var f_agi_op   = Ext.get('f_agi_op');

	var f_assay_val = Ext.get('f_assay_val');
	var f_pred_val  = Ext.get('f_pred_val');
	var f_ref_val   = Ext.get('f_ref_val');
	var f_info_val  = Ext.get('f_info_val');
	var f_num_val   = Ext.get('f_num_val');
	var f_chr_val   = Ext.get('f_chr_val');
	var f_agi_val   = Ext.get('f_agi_val');
	
	//Get the list of papers from the server
	Ext.Ajax.request({
		url : 'papers.php',
		method : 'GET',
		success : function(response) {
			var result = Ext.util.JSON.decode(response.responseText);

			if (result.success) {
				if (result.papers) {
					var box = document.getElementById('f_ref_val');
					
					var option = document.createElement("OPTION");
					option.setAttribute('value', '.');
					option.innerHTML = 'any paper';
					box.appendChild(option);
					
					//var html = "<option value='.'>any paper</option>";

					Ext.each(result.papers, function(paper) {
						var option = document.createElement("OPTION");
						option.setAttribute('value', ':' + paper.id + '(;|$)');
						option.innerHTML = '(' + paper.year + ') ' + paper.author;
						box.appendChild(option);
						//html += "<option value=':" + paper.id + "(;|$)'>(" + paper.year + ") " + paper.author + "</option>";
					});
					//f_ref_val.dom.innerHTML = html;
					//alert(html);
					//Reflow the element (annoying step required to satisfy internet fucking explorer)
					var next = box.nextSibling;
					var parent = box.parentNode;
					parent.removeChild(box);
					parent.insertBefore(box, next);
				}
				else {
					Ext.Msg.alert('Error', 'Failed to retrieve list of papers from the server');
					return;
				}
			}
			else {
				Ext.Msg.alert('Error', result.message);
				return;
			}
		},
		failure : function(response) {
			Ext.Msg.alert('Error', response.responseText);
			return;
		}
	});
	
	//Add functionality to the render controller
	f_render.on('change', function(event) {
		render();
	});
	
	//Add core functionality to buttons
	var buttons = [
		f_open, f_close, f_and, f_or, f_undo, f_reset, f_submit, 
		f_assay_add, f_pred_add, f_ref_add, f_info_add, f_num_add, f_chr_add, f_agi_add,
		f_assay_info, f_pred_info, f_ref_info, f_info_info, f_num_info, f_chr_info, f_agi_info
	];
	
	Ext.each(buttons, function(item) {
		item.unselectable();
		item.disabled = false;
		
		item.on('mouseover', function(event) {
			if (this.disabled) return;
			this.addClass('button_over');
		});
		item.on('mouseout', function(event) {
			if (this.disabled) return;
			this.removeClass('button_over');
			this.removeClass('button_down');
		});
		item.on('mousedown', function(event) {
			if (this.disabled) return;
			this.addClass('button_down');
		});
		item.on('mouseup', function(event) {
			if (this.disabled) return;
			this.removeClass('button_down');
		});
		item.disable = function() {
			this.disabled = true;
			this.addClass('button_disabled');
			this.removeClass('button_down');
			this.removeClass('button_over');
		};
		item.enable = function() {
			this.disabled = false;
			this.removeClass('button_disabled');
		};
	});
	
	//Set initial button states
	f_close.disable();
	f_and.disable();
	f_or.disable();
	f_undo.disable();
	f_reset.disable();
	f_submit.disable();
	
	//Add popup functionality to the info buttons
	var info_buttons = [
		f_assay_info, f_pred_info, f_ref_info, f_info_info, f_num_info, f_chr_info, f_agi_info
	];
	Ext.each(info_buttons, function(item) {
		this.help = this.dom.innerHTML;
		this.dom.innerHTML = '?';
		item.on('mouseup', function(event) {
			Ext.Msg.show({
			   title:'Information',
			   msg: this.help,
			   buttons: Ext.Msg.OK,
			   icon: Ext.MessageBox.INFO
			});			
		});
	});
	
	//Add specific functionality to toolbar buttons
	f_open.on('mouseup', function(event) {
		if (this.disabled) return;
		list.append({
			type:'open',
			value:'(',
			sql:'('
		});
		render();
	});
	f_close.on('mouseup', function(event) {
		if (this.disabled) return;
		list.append({
			type:'close',
			value:')',
			sql:')'
		});
		render();
	});
	f_and.on('mouseup', function(event) {
		if (this.disabled) return;
		list.append({
			type:'boolean',
			value:'AND',
			sql:'&&'
		});
		render();
	});
	f_or.on('mouseup', function(event) {
		if (this.disabled) return;
		list.append({
			type:'boolean',
			value:'OR',
			sql:'||'
		});
		render();
	});		
	f_undo.on('mouseup', function(event) {
		if (this.disabled) return;
		list.remove(list.last);
		render();
	});
	f_reset.on('mouseup', function(event) {
		if (this.disabled) return;
		list.clear();
		mark_valid(f_info_val);
		mark_valid(f_num_val);
		mark_valid(f_agi_val);
		render();
	});
	f_submit.on('mouseup', function(event) {
		if (this.disabled) return;
		
		//Build an array of query components
		var components = [];
		
		for (var node=list.first; node; node=node.next) {
			components.push({type:node.value.type, sql:node.value.sql || null});
		};
		
		//Convert to a JSON string
		var query = Ext.util.JSON.encode(components);
		
		//Pass the string to the grid and reload data
		grid.select(query);
	});
	
	//Add specific functionality to each of the query component addition buttons
	f_assay_add.on('mouseup', function(event) {
		if (this.disabled) return;
		var english = "";
		english += "<span class='column'>Protein location</span>";
		english += "<span class='operator'>" + selected_text(f_assay_op) + ' inferred by</span>'
		english += "<span class='column'>" + selected_text(f_assay_col) + '</span>';
		english += "<span class='operator'>to be in</span>";
		english += "<span class='value'>" + selected_text(f_assay_val) + '</span>';
		
		var sql = {
			column: f_assay_col.dom.value,
			operator: f_assay_op.dom.value,
			value: f_assay_val.dom.value
		};
		list.append({
			type:'condition',
			english:english,
			sql:sql
		});
		render();
	});
	f_pred_add.on('mouseup', function(event) {
		if (this.disabled) return;
		var english = "";
		english += "<span class='column'>Protein location</span>";
		english += "<span class='operator'>" + selected_text(f_pred_op) + ' predicted by</span>'
		english += "<span class='column'>" + selected_text(f_pred_col) + '</span>';
		english += "<span class='operator'>to be in</span>";
		english += "<span class='value'>" + selected_text(f_pred_val) + '</span>';
		
		var sql = {
			column: f_pred_col.dom.value,
			operator: f_pred_op.dom.value,
			value: f_pred_val.dom.value
		};
		list.append({
			type:'condition',
			english:english,
			sql:sql
		});
		render();
	});
	f_ref_add.on('mouseup', function(event) {
		if (this.disabled) return;
		var english = "";
		english += "<span class='column'>Protein location</span>";
		english += "<span class='operator'>" + selected_text(f_ref_op) + ' described in</span>'
		english += "<span class='value'>" + selected_text(f_ref_val) + '</span>';

		var sql = {
			column: f_ref_col.dom.value,
			operator: f_ref_op.dom.value,
			value: f_ref_val.dom.value
		};
		list.append({
			type:'condition',
			english:english,
			sql:sql
		});
		render();
	});
	f_info_add.on('mouseup', function(event) {
		if (this.disabled) return;
		
		//Validate the user provided value
		if (f_info_val.dom.value == '') {
			mark_invalid(f_info_val, 'This field must not be empty');
			return;
		}
		if (!new RegExp(f_info_val.dom.value)) {
			mark_invalid(f_info_val, 'Illegal regular expression entered');
			return;
		}
		mark_valid(f_info_val);
		
		var english = "";
		english += "<span class='column'>Protein information</span>";
		english += "<span class='operator'>" + selected_text(f_info_op) + ' keyword</span>'
		english += "<span class='value'>'" + f_info_val.dom.value + "'</span>";
		
		var sql = {
			column: f_info_col.dom.value,
			operator: f_info_op.dom.value,
			value: f_info_val.dom.value
		};
		list.append({
			type:'condition',
			english:english,
			sql:sql
		});
		render();
	});
	f_num_add.on('mouseup', function(event) {
		if (this.disabled) return;

		//Validate the user provided value
		if (f_num_val.dom.value == '') {
			mark_invalid(f_num_val, 'This field must not be empty');
			return;
		}
		if (parseFloat(f_num_val.dom.value) != f_num_val.dom.value) {
			mark_invalid(f_num_val, 'Value must be a number');
			return;
		}
		mark_valid(f_num_val);

		var english = "";
		english += "<span class='column'>" + selected_text(f_num_col) + "</span>";
		english += "<span class='operator'>" + selected_text(f_num_op) + '</span>'
		english += "<span class='value'>" + f_num_val.dom.value + '</span>';
		
		var sql = {
			column: f_num_col.dom.value,
			operator: f_num_op.dom.value,
			value: f_num_val.dom.value
		};
		list.append({
			type:'condition',
			english:english,
			sql:sql
		});
		render();
	}); 
	f_chr_add.on('mouseup', function(event) {
		if (this.disabled) return;
		var english = "";
		english += "<span class='column'>Underlying gene model</span>";
		english += "<span class='operator'>" + selected_text(f_chr_op) + '</span>'
		english += "<span class='column'>chromosome</span>";
		english += "<span class='value'>" + selected_text(f_chr_val) + "</span>";
		
		var sql = {
			column: f_chr_col.dom.value,
			operator: f_chr_op.dom.value,
			value: f_chr_val.dom.value
		};
		list.append({
			type:'condition',
			english:english,
			sql:sql
		});
		render();
	});
	f_agi_add.on('mouseup', function(event) {
		if (this.disabled) return;
		
		//Validate user input
		var input = f_agi_val.dom.value;
		
		if (input == '') {
			mark_invalid(f_agi_val, 'This field must not be empty');
			return;
		}
		//Make it all uppercase
		input = input.toUpperCase();
		
		input = input.replaceAll(' ' , ',');
		input = input.replaceAll("\t", ',');
		input = input.replaceAll("\n", ',');
		input = input.replaceAll("\r", ',');		
		input = input.replaceAll(',,', ',');
		input = input.trim();

		var raw_agis = input.split(',');
		var length = raw_agis.length;
		
		var safe_agis = new Array();
		var regexp = /^AT[1-5CM]G[0-9]{5}\.[1-9]$/;
		
		for (var i=0; i<length; i++) {
			var agi = raw_agis[i].trim();
			
			if (agi.length == 9) {
				agi += '.1';
			}
			//if (agi.length != 11) continue;
			if (!regexp.test(agi) || agi.length != 11) {
				mark_invalid(f_agi_val, 'Incorrectly formatted AGI value detected ('+agi+'). An example of a valid AGI is At1g01010.1');
				return;			
			}
			safe_agis.push(agi);
		}
                if (safe_agis.length ==0) {
                        return;
                }
		mark_valid(f_agi_val);
		
		var agis = safe_agis.join(',');
		f_agi_val.dom.value = agis;

		var english = "";
		english += "<span class='column'>Arabidopsis Gene Identifier</span>";
		english += "<span class='operator'>" + selected_text(f_agi_op) + '</span>'
		english += "<span class='value'>(" + agis + ')</span>';

		var sql = {
			column: f_agi_col.dom.value,
			operator: f_agi_op.dom.value,
			value: agis
		};
		list.append({
			type:'condition',
			english:english,
			sql:sql
		});
		render();
	});
	
	
	//Mark a form element as being invalid
	function mark_invalid(element, message) {
		Ext.Msg.show({
			title:'Validation Error',
			msg: message,
			buttons: Ext.Msg.OK,
			icon: Ext.MessageBox.ERROR
		});
		element.addClass('invalid');		
	}
	
	//Remove invalid marking from a form element
	function mark_valid(element) {
		element.removeClass('invalid');
	}
	
	//Get the selected text from a select box
	function selected_text(select) {
		var select = select.dom;
		return select.options[select.selectedIndex].text;
	}
	
	var query_box = document.getElementById('query_box');
	
	function enable_adds(flag) {
		if (flag) {
			//Ext.get('components').unmask();
			f_assay_add.enable(); 
			f_pred_add.enable(); 
			f_ref_add.enable(); 
			f_info_add.enable(); 
			f_num_add.enable(); 
			f_chr_add.enable(); 
			f_agi_add.enable();
			return;
		}
		//Ext.get('components').mask();
		f_assay_add.disable(); 
		f_pred_add.disable(); 
		f_ref_add.disable(); 
		f_info_add.disable(); 
		f_num_add.disable(); 
		f_chr_add.disable(); 
		f_agi_add.disable();
	}
	
	//The render routine is responsible for enabling / disabling buttons and displaying the current query
	function render() {
		query_box.innerHTML = '';
		var render_as_sql = f_render.dom.value == 'SQL';
		
		if (list.count == 0) {
			f_open.enable();
			f_close.disable();
			f_and.disable();
			f_or.disable();
			f_undo.disable();
			f_reset.disable();
			f_submit.disable();
			
			enable_adds(true);
			
			return;
		}
		f_undo.enable();
		f_reset.enable();
		
		var level = 0;
		
		for (var node=list.first; node; node=node.next) {
			var item = node.value;
			
			switch (item.type) {
				case 'open':
					query_box.appendChild(span('open', '('));
					level++;
					query_box.appendChild(newline());
					indent(level);
					break;
				case 'close':
					query_box.appendChild(newline());
					level--;
					indent(level);
					query_box.appendChild(span('close', ')'));
					break;
				case 'boolean':
					query_box.appendChild(newline());
					indent(level);
					query_box.appendChild(span('boolean', item.value));
					query_box.appendChild(newline());
					indent(level);
					break;
				case 'condition':
					if (render_as_sql) {
						query_box.appendChild(span('column', item.sql.column));					
						query_box.appendChild(span('operator', item.sql.operator));					
						query_box.appendChild(span('value', item.sql.value));					
					}
					else {
						query_box.innerHTML += item.english;
					}
					break;
			}
		}
		
		//Depending on the type of the last thing added, enable / disable form elements
		switch (list.last.value.type) {
			case 'open':
				f_open.enable();
				enable_adds(true);
				f_submit.disable();
				break;
			case 'close':
				if (level == 0) {
					f_close.disable();
					f_submit.enable();
				}
				break;
			case 'boolean':
				f_and.disable();
				f_or.disable();
				f_close.disable();
				f_open.enable();
				enable_adds(true);
				f_submit.disable();				
				break;
			case 'condition':
				enable_adds(false);
				if (level > 0) {
					f_close.enable();
				}
				f_and.enable();
				f_or.enable();
				f_open.disable();
				if (level == 0) {
					f_submit.enable();
				}
				break;
		}
	}
	
	//Generate a SPAN element for use in the query box
	function span(type, text) {
		var span = document.createElement('SPAN');
		span.className = type;
		if (text) span.innerHTML = text;
		return span;
	}

	//Get a new line element
	function newline() {
		return document.createElement('BR');
	}
	
	//Indent the query by the specified number of levels
	function indent(levels) {
		for (var i=0; i<levels; i++) {
			query_box.appendChild(span('spacer'));
		}
	}
}

//Show the selected tab
function select_tab(obj) {
	show_tab(this);
}
//Show a tab
function show_tab(tab) {
	if (active_tab) {
		active_tab.image.dom.src = 'img/suba_tab_normal.png';
		active_tab.section.setDisplayed(false);
	}
	active_tab = tab;
	active_tab.image.dom.src = 'img/suba_tab_selected.png';
	active_tab.section.setDisplayed(true);
}
