/// <reference path="../../../vendor/jquery/1.4.4/jquery.js"/>

//Create a namespace for filter methods to live
cn.filters = {};

// Set up behaviors for a single filter, given the DOM node (normally a div of class filter).
jQuery.makeFilter = function(filter)
{
	var $filter = $(filter);
	
	var filterTimeout = null;
	$filter.hover(
		function() {  if (filterTimeout) clearTimeout(filterTimeout); $filter.addClass("filter_over");},
		function() {
			if (filterTimeout) clearTimeout(filterTimeout);
			filterTimeout = setTimeout(function() {$filter.removeClass("filter_over")}, 50);
		}
	);
	
	var $filterValueInputs = $("[name=filter]",filter);

	var labels = $("label",filter);
	if (labels.length>0)
	{
		filter.filterLabel = $(labels.get(0)).text();
	}

	filter.fieldName = $($("[id$=field]",filter)[0]).val();

	// define "clear" function for each element in the filter
	$filterValueInputs.each(function() {
		this.clear = function () {
			if (this.type == "checkbox")
				this.checked = false;
			else
				$(this).val("");
		};
	});
	
	// define "clear" function for the filter by calling clear on each element in this filter
	filter.clear = function()
	{
		$filterValueInputs.each(function() {
			this.clear();
		});
	};
	
	filter.hasValue = function()
	{
		if ($filterValueInputs.length > 0)
		{
			var hasValue = true;
			for (var i = 0; i < $filterValueInputs.length; i++)
			{
				var value = $($filterValueInputs[i]).val();
				hasValue = (value != undefined && value != "" && hasValue);
			}
			return hasValue;
		}
		else
		{
			return false;
		}
	}
	
	filter.isValid = function()
	{
		// 1. single value filters: if filter overrides isValid then return its isValid, otherwise return true 
		// 2. list filters: return true only if : 
		//		2.1 all its children are valid (as defined in 1), AND
		//		2.2 all children are set, or all of them are not set
		
		var allChildrenValid = true;
		var allChildrenNull = true;
		var allChildrenHaveValue = true;

		$filterValueInputs.each(function() {
			// if this filter child overrides isValid (e.g., autocomplete filter), return its results, otherwise return true
			allChildrenValid = allChildrenValid && ($.isFunction(this.isValid) ? this.isValid() : true);
			
			thisValue = $(this).val();
			thisValueSet = (thisValue != undefined && thisValue != "");
			allChildrenNull = allChildrenNull && !thisValueSet;
			allChildrenHaveValue = allChildrenHaveValue && thisValueSet;
		})

		return allChildrenValid && (allChildrenNull || allChildrenHaveValue);
	}
	
	filter.markInvalid = function()
	{
		$filterValueInputs.each(function() {
			var valueIsValid = ($.isFunction(this.isValid) ? this.isValid() : true);
			var valueIsNull = $(this).val() == "";
			if (valueIsNull || !valueIsValid)
			{
				$(this).closest(".filterValueContainer").addClass("invalidFilter");
			}
		})
	}
	
	filter.clearInvalid = function() {
		$filterValueInputs.each(function() {
			var $container = $(this).closest(".filterValueContainer");
			if ($container.hasClass("invalidFilter"))
			{
				$container.removeClass("invalidFilter");
				clearErrorMessage($(".error"));
			}
		})
	}
	
	// Clear error-highlight whenever a dropdown in the filter changes. This covers
	// both dropdown filters and some geography filters.
	$("select", filter).change(function ()
	{
		filter.clearInvalid();
	});
	
	filter.setChangeHandlers = function(handler)
	{
		$("input,select", filter).each(function (index, input)
		{
			$(input).change(function (event)
			{
				handler(event);
			});
		});
		$(".updateOnKeyUp", filter).each(function (index, input)
		{
			$(input).keyup(function (event)
			{
				handler(event);
			});
		});
	}

	setupTextBoxFilters($filter);
}

setupTextBoxFilters = function($filter)
{
	var $textBoxFilters = $(".textBoxFilter", $filter);
	$textBoxFilters.each( function() {
		var $input = $(".tb_valueInput", $filter);
		var $displayValueInput = $(".tb_displayValueInput", $filter);
		var filterValuePrefix = $(this).attr("filterprefix");
		$input.hide();
		// We want to let the event bubble because the keyup may not be text
		// The idea is to incrementally populate $input.val so that when you
		// hit return to submit the form the value has been copied.  
		// See ticket #2878.
		$displayValueInput.keyup(function(e) {
		    $input.val(filterValuePrefix + $(this).val());
			$filter.change();
		});
	});
}

// Set up filters for a colleague/contact list. This is a list of filters, where you pick them from a
// dropdown list to make them visible, and then press a 'filter' button to apply any changes (by calling
// postFilterSubmit). Used in search. This should be called after makeFilter has been called on each of
// the filters inside the container (which is named with a selector-string in filterSelector, and
// contained in personsContainer).
setupFilters = function(filterSelector, personsContainer, targetSelector, postFilterSubmit)
{
	var filterContainer = $(filterSelector, personsContainer);
	var $filterContainer = $(filterContainer);
	var $filterForm = filterContainer.parents("form");
	var $addFilterDropDown = $(".add-filter-dropdown", filterContainer);
	var $fixedFilterDropDown = $(".fixed-filter-dropdown", filterContainer);
	var $filters = $(".filter", filterContainer);
	var $submit = $(".filterButton .button", filterContainer);
	var $footerRow = $(".filterList-footer", filterContainer);

	var filterHash = {};
	$filters.each(
		function()
		{
			var filter = this;
			var $filter = $(this);
			filterHash[$filter.attr("filterField")] = $filter;
			$(".remove", this).click(
				function()
				{
					var o = document.createElement("option");
					o.text = filter.filterLabel;
					o.value = $filter.attr("filterField");
					try
					{
						$addFilterDropDown[0].add(o, null); //standards compliant, doesn't work in IE 7 (or probably 6 either)
					}
					catch (ex)
					{
						$addFilterDropDown[0].add(o); //IE only
					}
					$filter.hide();
					$filter[0].clear();
				});
		});

	$addFilterDropDown.change(
		function()
		{
			var me = $(this);
			var $filter = filterHash[me.val()];
			if ($filter)
            {
			    $footerRow.before($filter);
			    $filter.show();
			    select_RemoveByValue(this, me.val());
            }
		}
	);

	$fixedFilterDropDown.change(
		function()
		{
			var me = $(this);
			var $filter = filterHash[me.val()];
			if ($filter)
            {
			    $filter.add($filter.siblings(".filter:visible")).toggle();
            }
		}
	);

	var filterValidateFunction = cn.filters.getValidateFunction($submit);
	var searchSubmitFunction = function(e, callback)
	{
		$.get(appendUrlParams($filterForm.attr("action"), getValidFiltersQueryString($filterForm)), function(data)
		{
			crossUpdate(targetSelector, data, personsContainer);
			crossUpdate(".resultsCount", data, personsContainer);
			postFilterSubmit(personsContainer);
			callback();
		});
		return true;
	}
	$submit.clickableButton({ beforeClick: filterValidateFunction, doClick: searchSubmitFunction });
}

cn.filters.getValidateFunction = function(button, otherForms)
{
	return function()
	{
		var form = $(button).parents("form");
		var filtersInvalid = $(".filtersInvalid", form);
		var filtersRequired = $(".filtersRequired", form);

		var forms = form.add(otherForms);
		clearInvalidFilters(forms);
		
		var validationResults = new ValidationResults(false);
		forms.each(function()
			{
				var form = $(this);
				validationResults.AddValidationResults(processFilterGroups(form, form.attr("requireValidFiltersOnSubmit") == "true"));
			}
		);

		if (validationResults.invalidFilters > 0 || !validationResults.HasRequiredFilters())
		{
			markInvalidFilters(forms);
			
			showErrorMessage($(".error"), "The search terms highlighted in red are incomplete. Please complete those search terms and resubmit the search.");
			
			return false;
		}
		else
		{
			return true;
		}
	};
};

processFilterGroups = function(containers, requireValidFiltersOnSubmit)
{
	var validationResults = new ValidationResults(requireValidFiltersOnSubmit);
	var filterGroups = $(".filter-group", containers);
	filterGroups.each(function() {
		var $me = $(this);
		var filters = $(".filter", $me);
		var requireValidFiltersOnSubmit = $me.hasClass("fixed-filters");
		validationResults.AddValidationResults(validateFilters(filters, requireValidFiltersOnSubmit));
	});
	return validationResults;
}

markInvalidFilters = function(containers)
{
	$(".filter", containers).each(function() {
		//Same commend about visibility as below in validateFilters
		if ($(this).css("display") != 'none')
		{
			this.markInvalid();
		}
	});
}

clearInvalidFilters = function(containers) {
	$(".filter", containers).each(function() {
		this.clearInvalid();
	});
}

validateFilters = function(filters, requireValidFiltersOnSubmit)
{
	var validationResults = new ValidationResults(requireValidFiltersOnSubmit);

	// We'd really like to use the jQuery visible selector here.
	// However jQuery 1.3.2 introduced some performance changes that 
	// broke the visible selector in IE6 and IE7 in some situations, hidden tables in particular
	// See the jQUery bug tracker http://dev.jquery.com/ticket/4673
	//	filters.filter(":visible").each(function()
	//	{
	//		if (this.hasValue())
	//		{
	//			validationResults.filtersWithValues++; ;
	//		}
	//		if (!this.isValid())
	//		{
	//			validationResults.invalidFilters++; ;
	//		}
	//	});

	filters.each(function()
	{
		switch(validateFilter(this))
		{
			case ValidationResult.invalid:
				validationResults.invalidFilters++;
				validationResults.filtersWithValues++;
				break;
			case ValidationResult.valid:
				validationResults.filtersWithValues++;
				break;
			case ValidationResult.empty:
				break;
		}
	});
	return validationResults;
};

// Validates the given filter and returns a ValidationResult enum
validateFilter = function(filter)
{
	// a huge hack to get around the visible bug described above in validateFilters.
	// We really only care about the 'display' property on the filter row (not if it is hidden by some parent element)
	// So this hack will for now do until jQuery bug 4673 is fixed  and works for IE6, IE7, IE8, FF3 and GC
	if ($(filter).css("display") != 'none')
	{
		if (!filter.isValid())
			return ValidationResult.invalid;
		else if (!filter.hasValue())
			return ValidationResult.empty;
		else
			return ValidationResult.valid;
	}
}

function ValidationResults(requireValidFiltersOnSubmit)
{
	this.requireValidFiltersOnSubmit = requireValidFiltersOnSubmit;
	this.filtersWithValues = 0;
	this.invalidFilters = 0;
	this.AddValidationResults = AddValidationResults;
	this.HasRequiredFilters = HasRequiredFilters;
	var childResults = [];
	
	function AddValidationResults(results)
	{
		this.filtersWithValues += results.filtersWithValues;
		this.invalidFilters += results.invalidFilters;
		childResults.push(results);
	}
	
	function HasRequiredFilters()
	{
		var hasRequired = this.filtersWithValues > 0 || !this.requireValidFiltersOnSubmit;
		if (hasRequired)
		{
			for (var i =0; i < childResults.length; i++)
			{
				hasRequired = hasRequired && childResults[i].HasRequiredFilters();
			}
		}
		return hasRequired;
	}
}

getValidFiltersQueryString = function(forms)
{
	return getValidFilters(forms).fieldSerialize();
}

getValidFilters = function(forms)
{
	return $(".filter:visible [name=filter]",forms)
		.filter(function () { 
			return $(this).closest(".filter")[0].hasValue(); 
		});
}

function validateRevenueFilter()
{
	var revenueValueStr = $(this).val();
	// Revenue filter value should look like FilterFieldName_revenue_123. Negative
	// numbers and numbers with leading zeroes are not allowed. Leading and trailing
	// whitespace is allowed.
	return revenueValueStr.match("^[a-zA-Z]*_revenue_\\s*[1-9][0-9]*\\s*$");
}


