/*
  type ahead object that represents all the options available for type ahead.
  each typeahead input fields has its own TypeAhead Object.
*/
function TypeAhead(element, taOptions) {
	this.options = taOptions;
	this.selectedIndex = 0;
	this.numberOfDisplayRows;
	this.numberOfDisplayColumns;
	this.incrementSelectedIndex = function() {
		if (this.options) {
			var start = this.selectedIndex;
			do {
				this.selectedIndex = ++this.selectedIndex % this.options.length;
			} while ((!this.options[this.selectedIndex].display && start != this.selectedIndex) || this.options[this.selectedIndex].isOptGroup  );
			// check if any are left to display
			if (!this.options[this.selectedIndex].display) {
				this.selectedIndex = 1;
				for (i = 0; i < this.options.length; i++) {
					this.options[i].reset();
				}
			}
		}
	}
	this.decrementSelectedIndex = function() {
		if (this.options) {
			var start = this.selectedIndex;
			do {
				this.selectedIndex = (--this.selectedIndex + this.options.length) % this.options.length;
			} while ((!this.options[this.selectedIndex].display && start != this.selectedIndex) || this.options[this.selectedIndex].isOptGroup);
			// check if any are left to display
			if (!this.options[this.selectedIndex].display) {
				this.selectedIndex = 1;
				for (i = 0; i < this.options.length; i++) {
					this.options[i].display = true;
				}
			}
		}
	}
	this.incrementSelectedIndexByOneColumn = function() {
		if (this.options && this.numberOfDisplayRows > 1) {
			this.selectedIndex = (this.selectedIndex + this.numberOfDisplayRows) % (this.numberOfDisplayRows * this.numberOfDisplayColumns);
			if (this.selectedIndex >= this.options.length) {
				this.selectedIndex += this.numberOfDisplayRows;
				this.selectedIndex %= this.numberOfDisplayRows * this.numberOfDisplayColumns;
			}
		}
	}
	this.decrementSelectedIndexByOneColumn = function() {
		if (this.options && this.numberOfDisplayRows > 1) {
			this.selectedIndex = this.selectedIndex - this.numberOfDisplayRows;
			if (this.selectedIndex < 0) {
				this.selectedIndex += this.numberOfDisplayRows * this.numberOfDisplayColumns;
				if (this.selectedIndex >= this.options.length) {
					this.selectedIndex -= this.numberOfDisplayRows;
				}
			}
		}
	}
	this.displayRegionOptions = performRegionOptionDisplayFiltering;
	this.matchOptions = function(element, isDisplayAll) {
		var matchedGroupLables = new Object();
		this.selectedIndex = 1;
		var matchLevel = 0;
		var optGroupMatchLevel = 0;
		// perform primary match
		for (i = 0; i < this.options.length; i++) {
			var match = this.options[i].primaryMatch(element);
			if (!this.options[i].isOptGroup) {
				if (match > matchLevel ) {
					matchLevel = match;
					this.selectedIndex = i;
				}
				if (match > 0 || isDisplayAll) {
					this.options[i].display = true;
				}
				else {
					this.options[i].display = false;
				}
			}
			else {
				if (match > optGroupMatchLevel ) {
					optGroupMatchLevel = match;
					matchedGroupLables[this.options[i].region] = "true";
				}
			}
		}
		
		// perform secondary match if a primary match wasn't found
		if (matchLevel == 0) {
			for (i = 0; i < this.options.length; i++) {
				if (this.options[i].secondaryMatch != null) {
					var match = this.options[i].secondaryMatch(element);
					if (!this.options[i].isOptGroup) {
						if (match > matchLevel) {
							matchLevel = match;
							this.selectedIndex = i;
						}
						if (match > 0 || isDisplayAll) {
							this.options[i].display = true;
						}
						else {
							this.options[i].display = false;
						}
					}
					else {
						if (match > optGroupMatchLevel ) {
							optGroupMatchLevel = match;
							if (matchedGroupLables[this.options[i].region] == null) {
								matchedGroupLables[this.options[i].region] = "true";
							}					
						}
					}					
				}
			}
		}
					
		// show all options if neither the primary or secondary matches were successful
		if (matchLevel == 0 && !isDisplayAll) {
			if(optGroupMatchLevel == 0) {
				for (i = 0; i < this.options.length; i++) {
					this.options[i].display = true;	
				}
				this.selectedIndex = 1;
			}
			else {
				// find all matched group lables
				for (i = 0; i < this.options.length; i++) {
					if (matchedGroupLables[this.options[i].region] != null) {
						this.options[i].display = true;	
					}
					else {
						this.options[i].display = false;	
					}
				}
				this.selectedIndex = 1;
			}
		}
		this.displayRegionOptions(this.options);
		// make sure we have a displayable element to display.
		if (!this.options[this.selectedIndex].display) {
			this.selectedIndex = 1;
			if (!this.options[0].display) {
				this.incrementSelectedIndex();
			}
		}
	}
	
	this.matchOptions(element, true);
}

function performRegionOptionDisplayFiltering() {
	var regionsToShow = new Object();
	// identify regions to display
	for (i = 0; i < this.options.length; i++) {
		if (!this.options[i].isOptGroup && this.options[i].display) {
			if (regionsToShow[this.options[i].region] == null) {
				regionsToShow[this.options[i].region] = "true";
			}
		}
	}
	// hide or show region options
	for (i = 0; i < this.options.length; i++) {
		if (this.options[i].isOptGroup) {
			if (regionsToShow[this.options[i].region] == "true") {
				this.options[i].display = true;
			}
			else {
				this.options[i].display = false;
			}
		}
	}
}

