function Querystring(qs) { // optionally pass a querystring to parse
	this.params = {};
	
	if (qs == null) qs = location.search.substring(1, location.search.length);
	if (qs.length == 0) return;

// Turn <plus> back to <space>
// See: http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4.1
	qs = qs.replace(/\+/g, ' ');
	var args = qs.split('&'); // parse out name/value pairs separated via &
	
// split out each name=value pair
	for (var i = 0; i < args.length; i++) {
		var pair = args[i].split('=');
		var name = decodeURIComponent(pair[0]);
		
		var value = (pair.length==2)
			? decodeURIComponent(pair[1])
			: name;
		
		this.params[name] = value;
	}
}

Querystring.prototype.get = function(key, default_) {
	var value = this.params[key];
	return (value != null) ? value : default_;
}

Querystring.prototype.contains = function(key) {
	var value = this.params[key];
	return (value != null);
}

function Filter(name, label, inputType, defaultValue)
{
	this.name = name;
	this.label = label;
	this.inputType = inputType;																			// valid type values: int, date, str, list
	this.defaultValue = defaultValue;
	this.values = new Array();
}


Filter.prototype.values_addItem = function(label, value)
{
	var item = {};
	item.label = label;
	item.value = value;
	this.values[this.values.length] = item;
}



function InitFilterItem(name, operator, value, bool)
{
	this.name = name;
	this.operator = operator;
	this.value = value;
	this.bool = bool;
}













	
	
	
	
	
function FilterGenerator(containerId, formId)
{
	this.filters = new Array();
	this.containerId = containerId;
	this.formId = formId;
	this.showUpdateButton = false;
	this.filterParentObj = null;
	this.generated = false;
	
	this.doFirstFilter = false;
	this.initName;
	this.initOperator;
	this.initValue;
	this.initFilters = [];
	this.useFiltersLabel = "Filter Results:";
	
	this.input_class = "";
	this.select_class = "";
	
	// used internally to keep track of the filters the user chooses
	this.currentFilters = new Array();
	
	// attach onload event
	var self = this;
	this.addLoadEvent(function() { self.init(); });
}

FilterGenerator.prototype.setupFirstFilter = function(name, operator, value)
{
	this.doFirstFilter = true;
	this.initName = name;
	this.initOperator = operator;
	this.initValue = value;
}

FilterGenerator.prototype.setupInitialFilters = function(initFilters)
{
	this.initFilters = initFilters;
}

FilterGenerator.prototype.init = function()
{
	// auto-update/populate the filter parameters on the page if this is a refresh
	var qs = new Querystring();
	var numFilters = qs.get("numFilters");
	if(numFilters && numFilters > 0)
	{
		document.getElementById(this.containerId + "_useFilters").click();
		for(var i=1; i<=numFilters; i++)
		{
			document.getElementById(this.containerId + "_filter_" + i + "_name").value = qs.get("filter_" + i + "_name");
			document.getElementById(this.containerId + "_filter_" + i + "_name").onchange();
			document.getElementById(this.containerId + "_filter_" + i + "_operator").value = qs.get("filter_" + i + "_operator");
			document.getElementById(this.containerId + "_filter_" + i + "_value").value = qs.get("filter_" + i + "_value");
			document.getElementById(this.containerId + "_filter_" + i + "_bool").value = qs.get("filter_" + i + "_bool");
			if(qs.get("filter_" + i + "_bool"))
				document.getElementById(this.containerId + "_filter_" + i + "_bool").onchange();
		}
	}
}


FilterGenerator.prototype.setOnUpdate = function(filterParentObj, func)
{
	if(typeof(func) == "function")
	{
		this.showUpdateButton = true;
		this.onUpdate = func;
		this.filterParentObj = filterParentObj;
	}
}	
	
	
FilterGenerator.prototype.addFilter = function(filter)
{
	this.filters[this.filters.length] = filter;
}
	
	
	
FilterGenerator.prototype.getFilter = function(filterName)
{
	var obj = null;
	for(var i=0; i<this.filters.length; i++)
	{
		if(this.filters[i].name == filterName)
		{
			obj = this.filters[i];
			break;
		}
	}
	return obj;
}
	
	
	
	
	
	
	




FilterGenerator.prototype.generateFilters = function()
{
	var container = document.getElementById(this.containerId);
	var t = document.createElement("table");
	var useFilterId = this.containerId + "_useFilters";
	t.setAttribute("cellPadding", 1);
	t.setAttribute("cellSpacing", 1);
	t.border = 0;
		var r = t.insertRow(-1);
		r.vAlign = "top";
		
			var c2 = r.insertCell(-1);
			c2.width = 25;
			c2.style.paddingTop = "2px";
				useFilters_checkbox = document.createElement("input");
				useFilters_checkbox.filterGenerator = this;
				useFilters_checkbox.value = "1";
				useFilters_checkbox.name = useFilterId;
				useFilters_checkbox.id = useFilterId;
				useFilters_checkbox.type = "checkbox";
				//useFilters_checkbox.filterId = userFilters_checkbox.id;
				useFilters_checkbox.onclick = function() { this.filterGenerator.toggleUse(useFilterId); }
			c2.appendChild(useFilters_checkbox);
			
			var c1 = r.insertCell(-1);
			if(this.useFiltersLabel.length > 0)
				c1.width = 90;
			c1.noWrap = true;
			//c1.align = "right";
			c1.style.paddingTop = "6px";
				useFilters_label = document.createElement("label");
				useFilters_label.setAttribute("for", useFilterId);
				useFilters_label.innerHTML = this.useFiltersLabel;
			c1.appendChild(useFilters_label);
			
			var c3 = r.insertCell(-1);
				var filter_table = document.createElement("table");
				filter_table.border = 0;
				filter_table.id = this.containerId + "_table";
			c3.appendChild(filter_table);
			
			if(this.showUpdateButton)
			{
				var c4 = r.insertCell(-1);
					var updateButton = document.createElement("input");
					updateButton.filterGenerator = this;
					updateButton.style.marginTop = "3px";
					updateButton.setAttribute("type", "button");
					updateButton.setAttribute("value", "Update");
					updateButton.style.fontSize = "smaller";
					updateButton.onclick = function() { this.filterGenerator.onUpdateWrapper(); };
				c4.appendChild(updateButton);
			}
			
	container.appendChild(t);		
	
	// setup a numFilters variable in the case this FilterGenerator is used to fill out a form
	if(this.formId)
	{
		var form = document.getElementById(this.formId);
		var numFilters = document.createElement("input");
		numFilters.type = "hidden";
		//numFilters.name = this.formId + "_numFilters";
		numFilters.name = "numFilters";
		numFilters.id = this.formId + "_numFilters";
		numFilters.value = 0;
		form.appendChild(numFilters);
	}
	
	if(this.doFirstFilter)
	{
		document.getElementById(this.containerId + "_useFilters").checked = true;
		this.toggleUse();
		document.getElementById(this.containerId + "_filter_1_name").value = this.initName;
		// added line below on 2008-11-07 (fixed bug where initial value doesn't set properly if it's a dropdown
		document.getElementById(this.containerId + "_filter_1_name").onchange();
		document.getElementById(this.containerId + "_filter_1_operator").value = this.initOperator;
		document.getElementById(this.containerId + "_filter_1_value").value = this.initValue;
	}
	
	if(this.initFilters.length > 0)
	{
		document.getElementById(this.containerId + "_useFilters").checked = true;
		this.toggleUse();
		
		for(var i=0; i<this.initFilters.length; i++)
		{
			document.getElementById(this.containerId + "_filter_" + (i+1) + "_name").value = this.initFilters[i].name;
			// added line below on 2008-11-07 (fixed bug where initial value doesn't set properly if it's a dropdown
			document.getElementById(this.containerId + "_filter_" + (i+1) + "_name").onchange();
			document.getElementById(this.containerId + "_filter_" + (i+1) + "_operator").value = this.initFilters[i].operator;
			document.getElementById(this.containerId + "_filter_" + (i+1) + "_value").value = this.initFilters[i].value;
			if(i+1 != this.initFilters.length)
			{
				document.getElementById(this.containerId + "_filter_" + (i+1) + "_bool").value = this.initFilters[i].bool;
				document.getElementById(this.containerId + "_filter_" + (i+1) + "_bool").onchange();
			}
		}
	}
}


FilterGenerator.prototype.onUpdateWrapper = function()
{
	this.onUpdate.apply(this.filterParentObj);
}










FilterGenerator.prototype.getFields = function()
{
	var fields = new Array();
	
	// numFilters
	fields[fields.length] = {};
	fields[fields.length-1].name = "numFilters";
	fields[fields.length-1].value = this.getNumRows();
	
	for(var i=1; i<=this.getNumRows(); i++)
	{
		// filter type
		fields[fields.length] = {};
		fields[fields.length-1].name = "filter_" + i + "_type";
		fields[fields.length-1].value = document.getElementById(this.containerId + "_filter_" + i + "_type").inputType;
	
		// filter name
		fields[fields.length] = {};
		fields[fields.length-1].name = "filter_" + i + "_name";
		fields[fields.length-1].value = document.getElementById(this.containerId + "_filter_" + i + "_name").value;
		
		// filter operator
		fields[fields.length] = {};
		fields[fields.length-1].name = "filter_" + i + "_operator";
		fields[fields.length-1].value = document.getElementById(this.containerId + "_filter_" + i + "_operator").value;
		
		// filter value
		if(document.getElementById(this.containerId + "_filter_" + i + "_value").inputType != "date")
		{
			fields[fields.length] = {};
			fields[fields.length-1].name = "filter_" + i + "_value";
			fields[fields.length-1].value = document.getElementById(this.containerId + "_filter_" + i + "_value").value;
		}
		else
		{
			fields[fields.length] = {};
			fields[fields.length-1].name = "filter_" + i + "_value_month";
			fields[fields.length-1].value = document.getElementById(this.containerId + "_filter_" + i + "_value_month").value;
			
			fields[fields.length] = {};
			fields[fields.length-1].name = "filter_" + i + "_value_day";
			fields[fields.length-1].value = document.getElementById(this.containerId + "_filter_" + i + "_value_day").value;
			
			fields[fields.length] = {};
			fields[fields.length-1].name = "filter_" + i + "_value_year";
			fields[fields.length-1].value = document.getElementById(this.containerId + "_filter_" + i + "_value_year").value;
		}
		
		// bool value
		fields[fields.length] = {};
		fields[fields.length-1].name = "filter_" + i + "_bool";
		fields[fields.length-1].value = document.getElementById(this.containerId + "_filter_" + i + "_bool").value;
	}
	
	return fields;
}


FilterGenerator.prototype.generateQueryString = function(href)
{
	var fields = this.getFields();
	for(var i=0; i<fields.length; i++)
		href = this.href_appendQueryString(href, fields[i].name, fields[i].value);
		
	return href;
}










FilterGenerator.prototype.generateFilter = function()
{
	var self = this;
	
	var table = document.getElementById(this.containerId + "_table");
		var r = table.insertRow(-1);
		r.rowNum = this.getNumRows();
			var c1 = r.insertCell(-1);
				var f_item = document.createElement("select");
				f_item.filterGenerator = this;
				f_item.className = this.select_class;
				f_item.name = "filter_" + r.rowNum + "_name";
				f_item.id = this.containerId + "_filter_" + r.rowNum + "_name";
				f_item.rowNum = r.rowNum;
				f_item.size = 1;
				f_item.onchange = function() { this.filterGenerator.updateRow(this.rowNum);  }
			c1.appendChild(f_item);
			for(var i=0; i<this.filters.length; i++)
			{
				f_item.options[f_item.options.length] = new Option(this.filters[i].label, this.filters[i].name);
			}
			
			var c2 = r.insertCell(-1);
			c2.align = "center";
				var f_operator = document.createElement("select"); 
				f_operator.className = this.select_class;
				f_operator.name = "filter_" + r.rowNum + "_operator";
				f_operator.id = this.containerId + "_filter_" + r.rowNum + "_operator";
				f_operator.size = 1;
				f_operator.style.textAlign = "center";
			c2.appendChild(f_operator);
			
			var c3 = r.insertCell(-1);
			c3.id = this.containerId + "_filter_" + r.rowNum + "_valueCell";
			
			var c4 = r.insertCell(-1);
				var f_bool = document.createElement("select");
				f_bool.className = this.select_class;
				f_bool.filterGenerator = this;
				f_bool.name = "filter_" + r.rowNum + "_bool";
				f_bool.id = this.containerId + "_filter_" + r.rowNum + "_bool";
				f_bool.rowNum = r.rowNum;
				f_bool.onchange = function() { this.filterGenerator.checkBools(this.rowNum); }
				f_bool.options[f_bool.options.length] = new Option("", "");
				f_bool.options[f_bool.options.length] = new Option("AND", "AND");
				f_bool.options[f_bool.options.length] = new Option("OR", "OR");
			c4.appendChild(f_bool);
				var f_type = document.createElement("input");
				f_type.type = "hidden";
				f_type.name = "filter_" + r.rowNum + "_type";
				f_type.id = this.containerId + "_filter_" + r.rowNum + "_type";
				f_type.rowNum = r.rowNum;
			c4.appendChild(f_type);	
			
			this.updateRow(r.rowNum);
}







FilterGenerator.prototype.toggleUse = function()
{
	// to start, display a first filter
	if(document.getElementById(this.containerId + "_useFilters").checked)
	{
		this.generateFilter();
	}
	// remove all filter rows
	else
	{
		var table = document.getElementById(this.containerId + "_table");
		while(table.getElementsByTagName("tr").length > 0)
			table.deleteRow(-1);
	}
	this.updateFilterCount();
}



FilterGenerator.prototype.getNumRows = function()
{
	var table = document.getElementById(this.containerId + "_table");
	var numRows = table.getElementsByTagName("tr").length;
	return numRows;
}


FilterGenerator.prototype.updateRow = function(rowNum)
{
	this.generateOperators(rowNum);
	this.generateValues(rowNum);
	this.generateItemType(rowNum);
}


FilterGenerator.prototype.checkBools = function(rowNum)
{
	var boolObj = document.getElementById(this.containerId + "_filter_" + rowNum + "_bool");
	
	// remove any filters below this row level
	if(boolObj.value == "")
	{
		var filterTable = document.getElementById(this.containerId + "_table");
		while(this.getNumRows() > rowNum)
			filterTable.deleteRow(-1);
	}
	// add row if there's not one already
	else if(this.getNumRows() == rowNum)
	{
		this.generateFilter();
	}
	this.updateFilterCount();
}



FilterGenerator.prototype.updateFilterCount = function()
{
	if(this.formId)
		document.getElementById(this.formId + "_numFilters").value = this.getNumRows();
}


FilterGenerator.prototype.generateOperators = function(rowNum)
{
	//alert(document.getElementById(this.containerId + "_filter_" + rowNum + "_name"));
	var itemObj = this.getFilter(document.getElementById(this.containerId + "_filter_" + rowNum + "_name").value);
	var operatorObj = document.getElementById(this.containerId + "_filter_" + rowNum + "_operator");
	operatorObj.options.length = 0;
	
	if(itemObj.inputType == "int" || itemObj.inputType == "date")
	{
		operatorObj.options[operatorObj.options.length] = new Option("=", "=");
		operatorObj.options[operatorObj.options.length] = new Option(">", ">");
		operatorObj.options[operatorObj.options.length] = new Option(">=", ">=");
		operatorObj.options[operatorObj.options.length] = new Option("<", "<");
		operatorObj.options[operatorObj.options.length] = new Option("<=", "<=");
	}
	else if(itemObj.inputType == "str")
	{
		operatorObj.options[operatorObj.options.length] = new Option("=", "=");
		if(itemObj.values.length == 0)
			operatorObj.options[operatorObj.options.length] = new Option("contains text", "like");
	}
	else if(itemObj.inputType == "list")
	{
		operatorObj.options[operatorObj.options.length] = new Option("=", "=");
	}
	else if(itemObj.inputType == "list_like")
	{
		operatorObj.options[operatorObj.options.length] = new Option("=", "like");
	}
	this.resizeOperators();
}



FilterGenerator.prototype.generateValues = function(rowNum)
{
	var itemObj = this.getFilter(document.getElementById(this.containerId + "_filter_" + rowNum + "_name").value);
	var valueObj; 
	var valueCell = document.getElementById(this.containerId + "_filter_" + rowNum + "_valueCell");
	valueCell.innerHTML = "";
	
	if(itemObj.inputType == "date")
	{
		valueObj = document.createElement("div");
		valueObj.id = this.containerId + "_filter_" + rowNum + "_value";
		valueObj.inputType = itemObj.inputType;
		
		date_month = document.createElement("select");
		date_month.name = "filter_" + rowNum + "_value_month";
		date_month.id = this.containerId + "_filter_" + rowNum + "_value_month";
		date_month.filterGenerator = this;
		date_month.size = 1;
		date_month.className = this.select_class;
		date_month.onchange = function() { this.filterGenerator.updateDays(this.filterGenerator.containerId + "_filter_" + rowNum + "_value"); };
		var monthNames = new Array("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");
		for(var i=0; i<12; i++)
			date_month.options[date_month.options.length] = new Option((i+1) + " - " + monthNames[i], i+1);
		
		date_day = document.createElement("select");
		date_day.name = "filter_" + rowNum + "_value_day";
		date_day.id = this.containerId + "_filter_" + rowNum + "_value_day";
		date_day.size = 1;
		date_day.className = this.select_class;
		
		date_year = document.createElement("select");
		date_year.name = "filter_" + rowNum + "_value_year";
		date_year.id = this.containerId + "_filter_" + rowNum + "_value_year";
		date_year.filterGenerator = this;
		date_year.size = 1;
		date_year.className = this.select_class;
		date_year.onchange = function() { this.filterGenerator.updateDays(this.filterGenerator.containerId + "_filter_" + rowNum + "_value"); };
		for(var i=1999; i<2010; i++)
			date_year.options[date_year.options.length] = new Option(i, i);
		
		valueObj.appendChild(date_month);
		valueObj.appendChild(date_day);
		valueObj.appendChild(date_year);
		
		valueCell.appendChild(valueObj);
		
		this.updateDays(this.containerId + "_filter_" + rowNum + "_value");
	}
	else
	{
		// use select element for a list
		if(itemObj.values.length > 0)
		{
			valueObj = document.createElement("select");
			valueObj.inputType = itemObj.inputType;
			valueObj.name = "filter_" + rowNum + "_value";
			valueObj.id = this.containerId + "_filter_" + rowNum + "_value";
			valueObj.size = 1;
			valueObj.className = this.select_class;
			
			for(var i=0; i<itemObj.values.length; i++)
				valueObj.options[valueObj.options.length] = new Option(itemObj.values[i].label, itemObj.values[i].value);
			
			valueCell.appendChild(valueObj);
		}
		
		// use text box for a user entry
		else
		{
			valueObj = document.createElement("input");
			valueObj.inputType = "text";
			valueObj.name = "filter_" + rowNum + "_value";
			valueObj.id = this.containerId + "_filter_" + rowNum + "_value";
			valueObj.className = this.input_class;
			if(itemObj.inputType == "int")
				valueObj.style.width = "50px";
			else
				valueObj.style.width = "150px";
				
			valueCell.appendChild(valueObj);
		}
	}
}





FilterGenerator.prototype.generateItemType = function(rowNum)
{
	var itemObj = this.getFilter(document.getElementById(this.containerId + "_filter_" + rowNum + "_name").value);
	document.getElementById(this.containerId + "_filter_" + rowNum + "_type").value = itemObj.inputType;
}











FilterGenerator.prototype.resizeOperators = function()
{
	var maxWidth = 0;
	for(var i=1; i<=this.getNumRows(); i++)
	{
		var width = document.getElementById(this.containerId + "_filter_" + i + "_operator").clientWidth;
		if(width > maxWidth)
			maxWidth = width;
	}
	
	for(var i=1; i<=this.getNumRows(); i++)
	{
		//document.getElementById(this.containerId + "_filter_" + i + "_operator").style.width = maxWidth + "px";
		
	}
}













FilterGenerator.prototype.href_appendQueryString = function(href, varName, varValue)
{
	if(href.indexOf('?') >= 0)
		href += "&" + varName + "=" + varValue;
	else
		href += "?" + varName + "=" + varValue;
	return href;
};



FilterGenerator.prototype.addLoadEvent = function(func) 
{
	if(window.addEventListener)
	{
		
		window.addEventListener("load", func, false);
	}
	else
		window.attachEvent("onload", func);
}


















FilterGenerator.prototype.isLeapYear = function(year)
{
   if ((year / 4)   != Math.floor(year / 4))   
		return false;
   if ((year / 100) != Math.floor(year / 100)) 
		return true;
   if ((year / 400) != Math.floor(year / 400)) 
		return false;
   return true;
}

FilterGenerator.prototype.updateDays = function(dateName)
{
	var daysNormal   = new Array( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
	var daysLeapYear = new Array( 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
	
	var objMonth = document.getElementById(dateName + '_month');
	var objDay = document.getElementById(dateName + '_day');
	var objYear = document.getElementById(dateName + '_year');
	var days = isLeapYear(objYear.value) ? daysLeapYear[parseInt(objMonth.value)-1] : daysNormal[parseInt(objMonth.value)-1];
	var oldDay = objDay.value == "" ? 1 : objDay.value;
	
	objDay.options.length = 0;
	for(var i=1; i<=days; i++)
		objDay.options[objDay.options.length] = new Option(i, i);
	if(oldDay > days)
		oldDay = days;
	objDay.value = oldDay;
}











