// This file depends on localized strings and functions currently located in:
// resources/new/<locale>/js/properties.js

var ALL_VALUE = "";
var ALL_VALUES_RE = /^(All||Any)?$/i;
// Chained basic search criteria: used for dropdown names, HTML div names, and QuickSearch property names
var SEARCHTYPE_NAME = "search";
var SEARCHTYPE_ROW = "qsSearchType";
var LOCATION_NAME = "location";
var LOCATION_ROW = "qsLocation";
var MAKE_NAME = "make";
var MAKE_ROW = "qsMake";
var MODEL_NAME = "model";
var MODEL_ROW = "qsModel";
var TRIM_NAME = "trim";
var TRIM_ROW = "qsTrim";
var VEHICLETYPE_NAME = "bodyType";
var VEHICLETYPE_ROW = "qsbodyType";
// Handy collections of fields
var CHAINED_FIELDS = [LOCATION_NAME, VEHICLETYPE_NAME, MAKE_NAME, MODEL_NAME, TRIM_NAME];
var allFieldsQS = null;
var criteriaList = null;
var isCIREnabled = false;

QuickSearchConfig = {
	defaultSearchType : "new",
	focusOnSubmit : true,
	locationLabel : ALL_LOCATIONS,
	makeLabel : ALL_MAKES,
	modelLabel : ALL_MODELS,
	optionAllSearchTypes : false,
	searchTypeLabel : ALL_TYPES,
	nullSearchTypes : true,
	trimLabel : ALL_TRIMS,
	displayOptionAllSearchTypes : function() { return QuickSearchConfig.optionAllSearchTypes; },
	displayNullSearchTypes : function() { return QuickSearchConfig.nullSearchTypes; },
	doFocusOnSubmit : function() { return QuickSearchConfig.focusOnSubmit; },
	getDefaultSearchType : function() { return QuickSearchConfig.defaultSearchType; },
	getLocationLabel : function() { return QuickSearchConfig.locationLabel; },
	getMakeLabel : function() { return QuickSearchConfig.makeLabel; },
	getModelLabel : function() { return QuickSearchConfig.modelLabel; },
	getSearchTypeLabel : function() { return QuickSearchConfig.searchTypeLabel; },
	getTrimLabel : function() { return QuickSearchConfig.trimLabel; },
	setDefaultSearchType : function(defaultSearchType) { QuickSearchConfig.defaultSearchType = defaultSearchType; },
	setDisplayOptionAllSearchTypes : function(optionAllSearchTypes) { QuickSearchConfig.optionAllSearchTypes = optionAllSearchTypes; },
	setDisplayNullSearchTypes : function(nullSearchTypes) { QuickSearchConfig.nullSearchTypes = nullSearchTypes; },
	setFocusOnSubmit : function(focusOnSubmit) { QuickSearchConfig.focusOnSubmit = focusOnSubmit; },
	setAllLocationsLabel : function(locationLabel) { QuickSearchConfig.locationLabel = locationLabel; },
	setAllMakesLabel : function(makeLabel) { QuickSearchConfig.makeLabel = makeLabel; },
	setAllModelsLabel : function(modelLabel) { QuickSearchConfig.modelLabel = modelLabel; },
	setAllSearchTypesLabel : function(searchTypeLabel) { QuickSearchConfig.searchTypeLabel = searchTypeLabel; },
	setAllTrimsLabel : function(trimLabel) { QuickSearchConfig.trimLabel = trimLabel; }
};

/** Encapsulates everything public in the search API. **/
function QuickSearch(jsDataObj) {
	this.jsdata = jsDataObj;
	this.searchForm = null;
	// initialize allFieldsQS to have advanced search criteria if necessary
	allFieldsQS = CHAINED_FIELDS;
	// populate properties with any preselected values, or "all"
	criteriaList = new CriteriaList();
	for (var i=0; i<allFieldsQS.length; i++) {
		criteriaList.add(new QuickSearchCriteria(allFieldsQS[i], ALL_VALUE, i));
	}
}
/** Disable and show message in drop downs if no inventory data is available */
QuickSearch.prototype.handleNoInventory = function(startCriteriaName) {
	if (!startCriteriaName) {
		this.searchForm[SEARCHTYPE_NAME].options.length = 0;
		this.searchForm[SEARCHTYPE_NAME].options[0] = new Option(NO_INVENTORY_AVAILABLE, "", true, true);
		this.searchForm[SEARCHTYPE_NAME].disabled = true;
		var startCriteriaName = LOCATION_NAME;
	}
    for (var i=criteriaList[startCriteriaName].index; i<allFieldsQS.length; i++) {
		if (this.searchForm[allFieldsQS[i]]) {
			criteriaList[allFieldsQS[i]].setOptions(this.searchForm[allFieldsQS[i]], [], new Option(NO_INVENTORY_AVAILABLE, ""));
			this.searchForm[allFieldsQS[i]].disabled = true;
		}
	}
	if (this.searchForm["quickSearchSubmitButton"]) this.searchForm["quickSearchSubmitButton"].disabled = true;
	return;
}
QuickSearch.prototype.init = function(searchForm) {
	this.searchForm = (searchForm) ? searchForm : document.forms[0];
	// verify the jsdata object has data
	var hasData = false;
	for (var searchType in this.jsdata){
		for (var location in this.jsdata[searchType]) {
			hasData = true;
			this["has" + searchType.capitalize()] = true;
			break;
		}
	}
	// if jsdo has no data, disable all fields and display "no inventory" message on search pages
	if (!hasData) {
		this.jsdata = new Object();
		this.handleNoInventory();
	} else {
		// initialize search criteria
		this.initCriteria();
		this.setSearchType(QuickSearchConfig.getDefaultSearchType());
	}
}
/** Initialize the "All" options for each search criteria, and populate the searchType dropdown */
QuickSearch.prototype.initCriteria = function() {
	this.populateSearchType();
	// set up chained criteria customized "All" options
	criteriaList[LOCATION_NAME].setAllOption(new Option(QuickSearchConfig.getLocationLabel(), ALL_VALUE, true, true));
	criteriaList[VEHICLETYPE_NAME].setAllOption(new Option(QuickSearchConfig.getSearchTypeLabel(), ALL_VALUE, true, true));
	criteriaList[MAKE_NAME].setAllOption(new Option(QuickSearchConfig.getMakeLabel(), ALL_VALUE, true, true));
	criteriaList[MODEL_NAME].setAllOption(new Option(QuickSearchConfig.getModelLabel(), ALL_VALUE, true, true));
	criteriaList[TRIM_NAME].setAllOption(new Option(QuickSearchConfig.getTrimLabel(), ALL_VALUE, true, true));
}
/** Populate the searchType dropdown with labels for each key in QuickSearch.jsdo */
QuickSearch.prototype.populateSearchType = function() {
	if (this.searchForm[SEARCHTYPE_NAME] && (this.searchForm[SEARCHTYPE_NAME].type == "select-one")) {
		this.searchForm[SEARCHTYPE_NAME].options.length = 0;
		if (QuickSearchConfig.displayOptionAllSearchTypes()) {
			this.searchForm[SEARCHTYPE_NAME].options[this.searchForm[SEARCHTYPE_NAME].options.length] = new Option(QuickSearchConfig.getSearchTypeLabel(), "");
		}
		for (var type in this.jsdata) {
			if (!QuickSearchConfig.displayNullSearchTypes() && !this["has" + type.capitalize()]) continue;
			this.searchForm[SEARCHTYPE_NAME].options[this.searchForm[SEARCHTYPE_NAME].options.length] = new Option(window[type.toUpperCase()], type);
		}
		if (this.searchForm[SEARCHTYPE_NAME].options.length == 0) this.handleNoInventory();
	}
}
/* Call in the onClick of the search dropdown */
QuickSearch.prototype.setSearchType = function(newType) {
	setSelected(this.searchForm[SEARCHTYPE_NAME], newType);
	if (newType && !this["has" + newType.capitalize()]) {
		this.handleNoInventory(LOCATION_NAME);
		return;
	}
	if (!window.editMode) {
	    for (var i=criteriaList[LOCATION_NAME].index; i<allFieldsQS.length; i++) {
			if (this.searchForm[allFieldsQS[i]]) this.searchForm[allFieldsQS[i]].disabled = false;
		}
		if (this.searchForm["quickSearchSubmitButton"]) this.searchForm["quickSearchSubmitButton"].disabled = false;
	}
	QuickSearchConfig.focusOnSubmit = false;
	criteriaList.resetCriteria(LOCATION_NAME);
	criteriaList[LOCATION_NAME].nodeList[criteriaList[LOCATION_NAME].nodeList.length] = this.jsdata[newType];
	criteriaList[LOCATION_NAME].addToValueMap(this.jsdata[newType]);
	criteriaList[LOCATION_NAME].resetNodeLists();
	criteriaList[LOCATION_NAME].set(this.searchForm);
	if (QuickSearchConfig.doFocusOnSubmit() && this.searchForm["quickSearchSubmitButton"]) this.searchForm["quickSearchSubmitButton"].focus();
}
/* Call in the onClick of the location dropdown */
QuickSearch.prototype.setLocation = function(newValue) {
	criteriaList[LOCATION_NAME].value = newValue;
	criteriaList[LOCATION_NAME].resetNodeLists();
	criteriaList[VEHICLETYPE_NAME].set(this.searchForm);
	if (QuickSearchConfig.doFocusOnSubmit() && this.searchForm["quickSearchSubmitButton"]) this.searchForm["quickSearchSubmitButton"].focus();
}
/* Call in the onClick of the vehicleType dropdown */
QuickSearch.prototype.setVehicleType = function(newValue) {
	criteriaList[VEHICLETYPE_NAME].value = newValue;
	criteriaList[VEHICLETYPE_NAME].resetNodeLists();
	criteriaList[MAKE_NAME].set(this.searchForm);
	if (QuickSearchConfig.doFocusOnSubmit() && this.searchForm["quickSearchSubmitButton"]) this.searchForm["quickSearchSubmitButton"].focus();
}
/* Call in the onClick of the make dropdown */
QuickSearch.prototype.setMake = function(newValue) {
	criteriaList[MAKE_NAME].value = newValue;
	criteriaList[MAKE_NAME].resetNodeLists();
	criteriaList[MODEL_NAME].set(this.searchForm);
	if (QuickSearchConfig.doFocusOnSubmit() && this.searchForm["quickSearchSubmitButton"]) this.searchForm["quickSearchSubmitButton"].focus();
}
/* Call in the onClick of the model dropdown */
QuickSearch.prototype.setModel = function(newValue) {
	criteriaList[MODEL_NAME].value = newValue;
	criteriaList[MODEL_NAME].resetNodeLists();
	criteriaList[TRIM_NAME].set(this.searchForm);
	if (QuickSearchConfig.doFocusOnSubmit() && this.searchForm["quickSearchSubmitButton"]) this.searchForm["quickSearchSubmitButton"].focus();
}
/* Call in the onClick of the trim dropdown */
QuickSearch.prototype.setTrim = function(newValue) {
	criteriaList[TRIM_NAME].value = newValue;
	if (QuickSearchConfig.doFocusOnSubmit() && this.searchForm["quickSearchSubmitButton"]) this.searchForm["quickSearchSubmitButton"].focus();
}
/** 
 * Submits the search form. 
 */
QuickSearch.prototype.submitForm = function() {
	try {
		if(isCIREnabled) {
			if(document.getElementsByName('search')[0].value == "preowned" && document.getElementsByName('certified')[0].value == "yes")
			document.quickSearchForm.search.options[1].value = "certified";
		}
		if (window.validateQuickSearch) validateQuickSearch(this.searchForm[SEARCHTYPE_NAME], this.searchForm[MAKE_NAME], this.searchForm[MODEL_NAME], this.searchForm[TRIM_NAME]);
		return true;
	} catch (err) {
		handleException(err);
		return false;
	}
}

/** Encapsulates one criteria in the inventory search dropdown. **/
function QuickSearchCriteria(name, value, index) {
	this.name = name;
	this.value = value;
	this.index = index;
	this.option = null;
	this.valueMap = {};
	this.nodeList = [];
	this.isPreSorted = false;
	return this;
}
/** Add values in an array to this criteria's valueMap. **/
QuickSearchCriteria.prototype.addToValueMap = function(node) {
	for (var key in node) this.valueMap[key] = node[key][0];
}
/** Do not populate model/trim dropdowns till a make has been selected. **/
QuickSearchCriteria.prototype.doPopulate = function() {
	return (!(((this.name == MODEL_NAME) && (criteriaList[MAKE_NAME].value == ALL_VALUE)) || ((this.name == TRIM_NAME) && (criteriaList[MODEL_NAME].value == ALL_VALUE))));
}
QuickSearchCriteria.prototype.doTruncate = function(optionsLength) { return (((this.name == MAKE_NAME) || (this.name == MODEL_NAME)) && (optionsLength == 1)); }
/** Create list of Options for this criteria, from a key/value map. **/
QuickSearchCriteria.prototype.getOptions = function() {
	var optionList = new Array();
	for (var key in this.valueMap) {
		if (key.trim()) optionList[optionList.length] = new Option(this.valueMap[key], key);
	}
	return optionList;
}
/** Get the value of the dropdown selection, or if it's blank, the value of the criteria object. **/
QuickSearchCriteria.prototype.getSelectedValue = function(someForm) {
	if (someForm[this.name]) return someForm[this.name].value;
	else return this.value;
}
/** Reset all fields holding selection and state values. **/
QuickSearchCriteria.prototype.reset = function() {
	this.nodeList = [];
	this.valueMap = {};
	this.value = ALL_VALUE;
}
/** Call this once per user click, for the criteria selected.  Initiate the node recursion. **/
QuickSearchCriteria.prototype.resetNodeLists = function() {
	// reset the nodeList of every criteria below the one being set (the one the user clicked).
	criteriaList.resetCriteria(allFieldsQS[this.index + 1]);
	// start recursing through each node in the nodeList, to set nodeLists down the food chain.
	for (var j=0; j<this.nodeList.length; j++) this.recurseNodes(this.nodeList[j], (this.index + 1));
}
/** Create a list of nodes for each criteria following the one clicked, filtered by selected values.
	Optionally populate valueMaps with the node data.  Also initiate advanced criteria population. **/
QuickSearchCriteria.prototype.recurseNodes = function(node, nextIndex) {
	var nextCriteria = criteriaList[CHAINED_FIELDS[nextIndex]];
	if (this.value == ALL_VALUE) {
		for (var key in node) {
			if (nextCriteria) {
				nextCriteria.nodeList[nextCriteria.nodeList.length] = node[key][1];
				if (nextCriteria.doPopulate()) nextCriteria.addToValueMap(node[key][1]);
				nextCriteria.recurseNodes(node[key][1], (nextIndex + 1));
			}
		}
	} else if (node[this.value]) {
		if (nextCriteria) {
			nextCriteria.nodeList[nextCriteria.nodeList.length] = node[this.value][1];
			if (nextCriteria.doPopulate()) nextCriteria.addToValueMap(node[this.value][1]);
			nextCriteria.recurseNodes(node[this.value][1], (nextIndex + 1));
		}
	}
}
/** Populate this criteria's dropdown with the values in its valueMap; call set for the next criteria in the chain. **/
QuickSearchCriteria.prototype.set = function(someForm) {
	// the requested value doesn't exist in the list of options (as from a bogus preselect)
	if ((this.value != ALL_VALUE) && !this.valueMap[this.value]) {
		this.value = ALL_VALUE;
		// reset all criteria under this one to ALL
		if (criteriaList.resetCriteria(allFieldsQS[this.index + 1]));
	}
	// retrieve the list of dropdown options
	var options = (this.isPreSorted) ? this.getOptions() : this.getOptions().sort(optionComparator);
	// make and model should not have "all" option if list is length 1
	var allOption = (this.doTruncate(options.length)) ? null : this.option;
	if (this.doTruncate(options.length)) {
		this.value = options[0].value;
		// manually create next criteria's valueMap from its nodeList, as this will not have been done in recurseNodes()
		var nextCriteria = criteriaList[CHAINED_FIELDS[this.index + 1]];
		for (var i=0; i<nextCriteria.nodeList.length; i++) nextCriteria.addToValueMap(nextCriteria.nodeList[i]);
	}
	// put this criteria's options in the appropriate dropdown
	this.setOptions(someForm[this.name], options, allOption);
	// set the next dropdown in the chained hierarchy, except trim which sets all advanced search criteria
	if ((this.index + 1) < CHAINED_FIELDS.length) criteriaList[CHAINED_FIELDS[this.index + 1]].set(someForm);
}
/** Set a custom "All" option for this criteria. **/
QuickSearchCriteria.prototype.setAllOption = function(option) { this.option = option; }
/** Set to true when valueMap is already in desired sort order (e.g. year). **/
QuickSearchCriteria.prototype.setIsPreSorted = function(isPreSorted) { this.isPreSorted = isPreSorted; }
/** Set Options for criteria's dropdown.  Optionally pass an "all" option if required. **/
QuickSearchCriteria.prototype.setOptions = function(dropdown, options, allOption) {
	if (!dropdown) return;
	dropdown.length = 0;
	var selectedIndex = 0;
	if (allOption) dropdown.options[0] = allOption;
	if (options && options.length) {
		for (var i=0; i<options.length; i++) {
			if (options[i].value == this.value) selectedIndex = dropdown.options.length;
			dropdown.options[dropdown.options.length] = options[i];
		}
	} else if (dropdown.options[0].value != ALL_VALUE) {
		dropdown.options[0] = new Option(ANY, ALL_VALUE, true, true);
	}
	dropdown.options[selectedIndex].selected = true;
}

/** Associative array of all criteria in the search form. **/
function CriteriaList() {}
/** Add a criteria to the list. **/
CriteriaList.prototype.add = function(criteria) {
	if (!criteria.name) return;
	this[criteria.name] = criteria;
}
/** Cycle through each criteria in the list and reset its values **/
CriteriaList.prototype.resetCriteria = function(startName) {
	for (var i=this[startName].index; i<allFieldsQS.length; i++) this[allFieldsQS[i]].reset();
}

/** Default validateQuickSearch function. Override in the layout/widget/include jsp if desired. **/
if (!window.validateQuickSearch) {
	validateQuickSearch = function(searchTypeDropdown, makeDropdown, modelDropdown, trimDropdown) {
		if (isEmpty(searchTypeDropdown.value)) return false;
		return true;
	}
}

/** Case-insensitive alpha sort, e.g. White, white, Yellow **/
function alphaComparator(a, b) {
	if (a.toLowerCase() > b.toLowerCase()) return 1;
	else if (a.toLowerCase() < b.toLowerCase()) return -1;
	else return 0;
}
/** Numeric sort, e.g. 1, 2, 10 **/
function numberComparator(n1, n2) { return n1 - n2; }
/** Case-insensitive alpha sort on Options **/
function optionComparator(a, b) { return alphaComparator(a.text, b.text); }
/** Trim whitespace off the start and end of a string **/
String.prototype.trim = function() { return this.replace(/^\s*([^\s]*)\s$/g, "\1"); }
/** Capitalize the first letter of a string */
String.prototype.capitalize = function() {
	var cap = new RegExp("^([a-z])").exec(this)[1].toUpperCase();
	return this.replace(/^[a-z]/, cap);
}
/** Return an array of keys in a map **/
function toArray(map) {
	var array = [];
	for (var key in map) array[array.length] = key;
	return array;
}



