//
// File : rtwgmap-filtering.js
//
// Description : Core Javascript functions for advanced Filtering on an RTWGMap implementation. 
//
// Contents    : 
//               
//                                       
//
//

var filters = [];
var filterMsgConnector = " and ";
var filterMsgSuffix = "";

var selectedFilters = [];

//
// get all the filters for the map
//    
function getFilters() {
	eval(getDataProviderClassName()).getFilters(returnFilters);
}

//
// Callback for getFilters()
//
var returnFilters = function(data) {
	if (data != null) {
		selectBoxes = [];
		filterMsgConnector = " and ";
		filterMsgSuffix = "";

		var container = document.getElementById("advFilterContainer");

		var filterBySelectBox = document.createElement("select");
		filterBySelectBox.id = "filterBy";
		filterBySelectBox.onchange = filterChanged;
		container.appendChild(filterBySelectBox);
		if (data.length == 1) {
			// no need to show this select box
			filterBySelectBox.className = 'hidden';
		} else {
			// add a divider under the "filterby" select box
			container.appendChild(document.createElement("br"));
		}

		for ( var i = 0; i < data.length; i++) {
			filters[i] = data[i];

			// create the filter by <blat> option
			filterBySelectBox.appendChild(createSelectOption(filters[i]));

			// create the a select box for each child of 'Filter'
			if (filters[i].children) {
				filters[i].selectBoxes = new Array();

				for ( var c = 0; c < filters[i].children.length; c++) {
					var filter = filters[i].children[c];
					var filterId = filter.id;
					if (!filterId) {
						filterId = c;
						filters[i].id = filterId;
					}

					//create a select box for this filter
					var selectBox = createSelectBox(filter);
					selectBox.onchange = filterChanged;
					selectBox.setAttribute("style", "width: 175px");
					if (selectBox.width)
						selectBox.width = 125;

					//create the container/panel for the select box with it's label
					var selContainer = document.createElement("div");
					//filters[i].selectBoxes[c] = selContainer;	
					filters[i].selectBoxes[c] = selectBox;
					container.appendChild(selContainer);
					selContainer.className = 'hidden';

					//add filter/selectbox label
					//selContainer.appendChild( document.createTextNode(filter.label + ':' ) );
					selContainer.appendChild(selectBox);
				}
			}
		}
		setDefaultFilter();
	}
}

var isFiltering = function() {
	return selectedFilters.length > 0;
}

//
// returns true if the markerObj passes ALL the selected filters (AND logic)
//
function matchesAllSelectedFilters(markerObj) {
	var match = true;

	for ( var i = 0; i < selectedFilters.length; i++) {
		var filter = selectedFilters[i];

		if (!filter.propertyMap)
			continue;

		var filterPropertyName = filter.propertyMap.key;
		var filterPropertyValue = filter.propertyMap.value;

		if (!markerObj.additionalInfo)
			return false;

		var value = eval("markerObj." + filterPropertyName);

		if (value == null || value != filterPropertyValue)
			return false; //has to match all filters!?
	}

	return match;
}

//
// Returns a natural language message (string) that
// represents the selected filters with a count of the
// number of listings that matched
//    
function getFilterMsg(filteredMarkers, noun) {
	if (selectedFilters.length == 0)
		return "";

	// get the visible markers' bounds
	var bounds = getVisibleMarkersBounds();
	var panZoomUrl = null;
	if (bounds && map && map.getBounds() && !(map.getBounds().contains(bounds.getNorthEast()) && map.getBounds().contains(bounds.getSouthWest()))) {
		// let the user pan/zoom to the visible markers 
		// if they aren't (all) visible
		panZoomUrl = "<a alt='Zoom to visible " + noun + "s' href='javascript:panZoomToVisibleMarkers();'>";
	}

	var indicative = "";
	var verbIndex;
	if (filteredMarkers.length == 0) {
		indicative += "are no " + noun + " ";
		verbIndex = 1;
	} else {
		if (filteredMarkers.length == 1) {
			indicative += " is only ";
			if (panZoomUrl)
				indicative += panZoomUrl;

			if (noun.match(/s$/)) {
				// strip off the "s"    		
				indicative += "one " + noun.substring(0, noun.length - 1);
			} else
				indicative += "one " + noun;
			verbIndex = 0;
		} else if (filteredMarkers.length > 1) {
			indicative += " are ";
			if (panZoomUrl)
				indicative += panZoomUrl;
			indicative += filteredMarkers.length + " " + noun;
			verbIndex = 1;
		}
		if (panZoomUrl)
			indicative += "</a>";
		indicative += " ";
	}

	// get a list of the components of the natural language string
	var nlComponents = new Array();
	var verbs = new Array();
	for ( var i = 0; i < selectedFilters.length; i++) {
		var currentVerb = selectedFilters[i].nlVerbs[verbIndex];
		var label = selectedFilters[i].label;
		if (selectedFilters[i].propertyMap != null) {
			verbs[currentVerb] = label;
			nlComponents[nlComponents.length] = {
				verb : currentVerb,
				type : label
			};
		}
	}

	// get the number of verbs
	var numOfVerbs = 0;
	for ( var k in verbs) {
		numOfVerbs++;
	}

	var msg = new Array();

	msg.push("<span>There " + indicative);
	msg.push("that ");
	var currentVerb = nlComponents[0].verb;
	msg.push(currentVerb + " ");

	for ( var i = 0; i < nlComponents.length; i++) {
		if (nlComponents[i].verb != currentVerb) {
			// verbage changed
			currentVerb = nlComponents[i].verb;
			msg.pop(); // get rid of the comma

			if (numOfVerbs <= 2 || i > 0 && i + 1 >= nlComponents.length)
				msg.push(filterMsgConnector); //" and ");
			else
				msg.push(", ");
			msg.push(currentVerb + " ");

		} else if (i > 0 && i + 1 >= nlComponents.length) {
			//only one more nlcomponent left
			msg.pop();
			msg.push(filterMsgConnector);//" and ");	        	      
		}

		msg.push(nlComponents[i].type);

		msg.push(", ");
	}

	msg.pop(); // get rid of the comma
	msg.push("</span>");

	var str = "";
	for ( var i = 0; i < msg.length; i++)
		str += msg[i];

	if (filterMsgSuffix && filterMsgSuffix.length > 0)
		str += filterMsgSuffix;

	return str;

}

//
// shows only the Markers that match a filter
//
// Uses the function 'matchesAllSelectedFilters(markerObj) to determine
// if the marker should be visible.
//
// Implementors should override matchesAllSelectedFilters or carefully
// maintain the list of selected filters in the selectedFilters[] array
//
function applySelectedFilters() {
	var filteredMarkers = [];
	var gmarker = 0;

	if (directions != null)
		//directions.clear();
		directions.setMap(null);

	//hide all the markers
	for (m in gmarkers) {
		//gmarkers[m].hide();
		gmarkers[m].setVisible(false);
	}

	var j = 0;
	// 
	// show or hide each marker as required
	//
	for ( var m = 0; m < markerObjs.length; m++) {
		//
		// Filter by selected nodes
		//
		if (matchesAllSelectedFilters(markerObjs[m])) {

			// (re)set the marker's color to the current filter if specified
			//if(selectedFilters[0].color) {
			//	  setGMarkerColor(markerObjs[m], selectedFilters[0].color);
			//}

			var info = markerObjs[m].infoHtml;
			info += "<p/>";
			info += "<span class=\"smallTextCenter\"><a href=\"javascript:zoomIn('" + markerObjs[m].id + "');\">Zoom In</a>"
					+ "</span>&nbsp;&nbsp;";

			show(markerObjs[m]);

			// add it to the resultset for display on the sidelisting
			filteredMarkers[j++] = markerObjs[m];
		}
	}

	var filter = {
		label : getSideListingsLabel()
	};
	globalRegion = filter;
	// display on the sidelisting
	returnFilteredMarkers(filteredMarkers);

	//
	//update the msg string
	//      
	var noun = markerInfo.markerTypeLabel;
	updateFilterResultMsg(filteredMarkers, noun);
}

//
// overrideable function for updating the filtered results msg(s)
//    
function updateFilterResultMsg(filteredMarkers, noun) {
	if (!loading) {
		document.getElementById("filters").innerHTML = getFilterMsg(filteredMarkers, noun);
	}
}

function createSelectBox(filter) {
	var selectBox = document.createElement("select");
	selectBox.id = "select" + filter.id;

	if (filter.children) {
		for ( var cc = 0; cc < filter.children.length; cc++) {
			selectBox.appendChild(createSelectOption(filter.children[cc]));
		}
	}

	return selectBox;
}

function createSelectOption(filter) {
	var _option = document.createElement("OPTION");
	_option.value = filter;
	_option.innerHTML = filter.label;

	return _option;
}

function filterByChanged() {
	var filterBy = filters[document.getElementById("filterBy").selectedIndex];
	if (filterBy.label.indexOf("Equipment" == -1))
		filterMsgSuffix = " Equipment";

	filterChanged();
}

var filterChanged = function() {
		//map.closeInfoWindow(); //TODO This doesn't work anymore.
	if(infoWindow && infoWindow.isOpen())//infoWindow.getMap())
		infoWindow.close();

	//hide all the select boxes
	for ( var i = 0; i < filters.length; i++) {
		filter = filters[i];
		for (s = 0; s < filters[i].selectBoxes.length; s++) {
			filters[i].selectBoxes[s].parentNode.className = 'hidden';
			filters[i].selectBoxes[s].className = 'hidden';
		}
	}

	if (isFiltering()) {
		// only show the select boxes for the current filterby selection
		var index = document.getElementById("filterBy").selectedIndex;
		var filterBy = filters[index];
		for (s = 0; s < filterBy.selectBoxes.length; s++) {
			filterBy.selectBoxes[s].parentNode.className = 'visible';
			filterBy.selectBoxes[s].className = 'visible';
		}

		selectedFilters = [];

		if (filterBy.children) {
			for ( var c = 0; c < filterBy.children.length; c++) {
				//set the selected filters
				var filter = filterBy.children[c];
				var selectBox = filterBy.selectBoxes[c];
				selectBox.className = 'visible';
				index = selectBox.selectedIndex; //selectBox.value doesn't work !?
				var filter = filter.children[index];
				selectedFilters[selectedFilters.length] = filter;
			}
		}
	}

	if (isFiltering()) {
		applySelectedFilters();
	} else {
		document.getElementById("filters").innerHTML = "";
		manageMarkers(null, null);
	}

	//
	// Zoom out on the map until at least one marker
	// is visiable
	//     
	panZoomToAtLeastOneVisibleMarker();
}

//
// pause for x milliseconds
//
function pausefor(millis) {
	var date = new Date();
	var curDate = null;

	do {
		curDate = new Date();
	} while (curDate - date < millis);
}

function setDefaultFilter() {
	if (!isFiltering() || gmarkers.length == 0)
		return;

	//
	// wait for the filters to be loaded - this
	// can be tough to sync with different load times
	// for the markers, filters, etc (diff on each browser)
	//
	var filterBy = document.getElementById("filterBy");
	if (!filterBy) {
		return;
	}

	// only show the select boxes for the current filterby selection
	var index = filterBy.selectedIndex;
	var filterBy = filters[index];
	for (s = 0; s < filterBy.selectBoxes.length; s++) {
		filterBy.selectBoxes[s].parentNode.className = 'visible';
		filterBy.selectBoxes[s].className = 'visible';
	}

	selectedFilters = [];

	if (filterBy.children) {
		for ( var c = 0; c < filterBy.children.length; c++) {
			//set the selected filters
			var filter = filterBy.children[c];
			var selectBox = filterBy.selectBoxes[c];
			selectBox.className = 'visible';
			index = selectBox.selectedIndex; //selectBox.value doesn't work !?
			var filter = filter.children[index];
			selectedFilters[selectedFilters.length] = filter;
		}
	}

	applySelectedFilters();
}
