/*
Requires YUI includes:

yahoo/yahoo-min.js
event/event-min.js
connection/connection-min.js
animation/animation-min.js
yahoo-dom-event/yahoo-dom-event.js
tools/tools-min.js
*/

/*
Requires the array to be already sorted.

If the key exists, returns its index.

Otherwise, returns the negative of the index
where the key should be inserted.
*/

Array.prototype.binarySearch = function(key)
{
	var low = 0;
	var high = this.length - 1;
	var mid, mid_val;

	while (low <= high)
	{
		mid = (low + high) >>> 1;
		mid_val = this[mid];

		if (mid_val < key)
		{
			low = mid + 1;
		}
		else if (mid_val > key)
		{
			high = mid - 1;
		}
		else
		return mid;
	}
	return -(low + 1);
}

Search_Params_Handler = function(search_params, result_params)
{
	if (search_params)
	{
		this.search = search_params;
	}
	else
	{
		this.search = { };
	}

	if (result_params)
	{
		this.result = result_params;
	}
	else
	{
		this.result = { };
	}

	this.pagination = { };
	this.encoded_param_string = '';
	this.last_step = 1;
}

/*
General functions to set search and result parameters

Optional step parameter is used for multi-step searches in which
each step searches within the previous step's results
*/

Search_Params_Handler.prototype.setSearchParam = function(param, value, step)
{
	if (!step)
	{
		step = 1;
	}

	if (!this.search[step])
	{
		this.search[step] = new Object();
	}

	if (step > this.last_step)
	{
		this.last_step = step;
	}

	if (value)
	{
		this.search[step][param] = value;
	}
	else
	{
		delete this.search[step][param];
	}

	this.encoded_param_string = '';
}

Search_Params_Handler.prototype.setResultParam = function(param, value)
{
	this.result[param] = value;
	this.encoded_param_string = '';
}

/*
Functions to set common parameters
*/

Search_Params_Handler.prototype.setPage = function(page)
{
	this.pagination['page'] = page;
	this.encoded_param_string = '';
}

Search_Params_Handler.prototype.setPageMax = function(page_max)
{
	this.pagination['page_max'] = page_max;
	this.encoded_param_string = '';
}

Search_Params_Handler.prototype.setSearchType = function(search_type, step)
{
	this.setSearchParam('search_type', search_type, step);
}

Search_Params_Handler.prototype.setLibraryContainerSchema = function(lib_cont_schema_id)
{
	if (!this.result['library'])
	{
		this.result['library'] = { };
	}
	this.result['library']['lib_cont_schema_id'] = lib_cont_schema_id;
	this.encoded_param_string = '';
}

Search_Params_Handler.prototype.setLibraryContainerField = function(container_field_params)
{
	if (!this.result['library'])
	{
		this.result['library'] = { };
	}
	this.result['library']['container_field'] = container_field_params;
	this.encoded_param_string = '';
}

Search_Params_Handler.prototype.setSitemapNode = function(sitemap_node_params)
{
	this.setResultParam('sitemap_node_id', sitemap_node_params);
}

Search_Params_Handler.prototype.setLanguage = function(language_id)
{
	this.setResultParam('language_id', language_id);
}

Search_Params_Handler.prototype.setCatalog = function(catalog_id)
{
	this.setResultParam('catalog_id', catalog_id);
}

Search_Params_Handler.prototype.getEncodedParamString = function()
{
	if (this.encoded_param_string == '')
	{
		delete this.encoded_param_string; // Do not include in param string

		for (var param in this.pagination)
		{
			this.search[this.last_step][param] = this.pagination[param];
		}

		encoded_param_string = YAHOO.Tools.JSONEncode(this);
		this.encoded_param_string = encoded_param_string;
	}

	return this.encoded_param_string;
}

Search_Results_Handler = function(params)
{
	if (params)
	{
		var search_params_obj = params['search_params_handler'];

		if (search_params_obj)
		{
			this.search_params_handler = search_params_obj;
		}
		else
		{
			this.search_params_handler = new Search_Params_Handler();
		}

		this.url = params['url'];
		this.action = params['action'];
	}
}

Search_Results_Handler.prototype.setCallback = function(callback)
{
	this.results_callback = callback;
}

Search_Results_Handler.prototype.requestResults = function()
{
	var search_params_string = this.search_params_handler.getEncodedParamString();
	var request = YAHOO.util.Connect.asyncRequest('POST', this.url, this.results_callback, '&action='+this.action+'&search_params='+search_params_string);
}

Search_Results_Handler.prototype.showPage = function(page)
{
	if (!page)
	{
		page = 1;
	}

	this.search_params_handler.setPage(page);
	this.requestResults();
}

displaySearchResultsList = function(search_output, container, params)
{
	if (!container)
	{
		return false;
	}

	container.innerHTML = '';

	if (!search_output)
	{
		return false;
	}
	if (!search_output['results'])
	{
		return false;
	}

	var event_queue = new Array();

	for (var i = 1; i <= search_output['total']; i++)
	{
		var row_container = getResultsRowDiv(search_output['results'][i]);
		row_container.id = 'resultRow'+i;
		if (params['animate_results'])
		{
			YAHOO.util.Dom.setStyle(row_container, 'opacity', '0');
		}
		container.appendChild(row_container);

		event_queue[i] = new Object();

		var anim_1 = new YAHOO.util.Anim(row_container.id, { opacity: { from: 0, to: 0.5 } }, 0.05, YAHOO.util.Easing.easeOut);
		anim_1.cit_anim_idx = i;

		event_queue[i]['anim_1'] = anim_1;

		var anim_2 = new YAHOO.util.Anim(row_container.id, { opacity: { from: 0.5, to: 1 } }, 0.05, YAHOO.util.Easing.easeOut);
		anim_2.cit_anim_idx = i;

		event_queue[i]['anim_2'] = anim_2;
	}

	if (params['animate_results'])
	{
		for (var i = 2; i <= event_queue.length; i++)
		{
			var prev_anim_1 = event_queue[i - 1]['anim_1'];

			prev_anim_1.onComplete.subscribe(function()
			{
				var prev_anim_2 = event_queue[this.cit_anim_idx]['anim_2'];
				prev_anim_2.animate();

				try
				{
					var next_anim_1 = event_queue[this.cit_anim_idx + 1]['anim_1'];
					next_anim_1.animate();
				}
				catch(e) { }
			}
			)
		}

		event_queue[1]['anim_1'].animate();
	}

	return true;
}

/*
displaySearchResults
* Calls functions: getResultsRowDiv, getPaginationHTML

Gets the search results and pagination HTML and puts it in
containers.
*/

displaySearchResults = function(o)
{
	var params = o.argument[0];
	var search_output = eval("(" + o.responseText + ")");
	var results_container, pagination_container, result_count_container;

	if (search_output['redirect_url'] && params['auto_redirect'])
	{
		window.location.href = search_output['redirect_url'];
		return true;
	}

	if (params['results_container'])
	{
		var display_result = displaySearchResultsList(search_output, params['results_container'], params);

		if (params['view_all_button'] && params['hide_all_button'])
		{
			var view_all_button_style = display_result ? 'none' : '';
			var hide_all_button_style = display_result ? '' : 'none';
			YAHOO.util.Dom.setStyle(params['view_all_button'].id, 'display', view_all_button_style);
			YAHOO.util.Dom.setStyle(params['hide_all_button'].id, 'display', hide_all_button_style);
		}
	}

	if (params['pagination_container'])
	{
		var html = getPaginationHTML(search_output, params);
		params['pagination_container'].innerHTML = html;
	}

	if (params['result_count_container'])
	{
		var result_count = search_output['abs_total'];
		params['result_count_container'].innerHTML = result_count;
	}
}

/*
getResultsRowDiv
* Input: Results row array
* Output: Div displaying product/category
*/

getResultsRowDiv = function(object_data)
{
	var container = document.createElement('div');
	container.className = 'product';

	var html = '';

	try
	{
		if (object_data['library']['image']['url'])
		{
			html += '<img src="'+object_data['library']['image']['url']+'" width="'+object_data['library']['image']['width']+'" height="'+object_data['library']['image']['height']+'" />';
		}
	}
	catch(e) { }

	html += '<h3><a href="'+object_data['url']+'">'+object_data['sales_code']+'</a></h3>';

	try
	{
		if (object_data['library']['description'])
		{
			html += '<p>'+object_data['library']['description']+'</p>';
		}
	}
	catch(e) { }

	html += '<div class="clearMargins"></div>';

	container.innerHTML = html;

	return container;
}

/*
getPaginationHTML
* Input: Search results array, params array
* Output: Search results pagination HTML

*/

getPaginationHTML = function(search_output, params)
{
	var current_page = parseInt(search_output['page']);
	var page_total = parseInt(search_output['page_total']);
	var pagination_function_name = params['pagination_function_name'];

	if (!search_output['results'] || !pagination_function_name)
	{
		return '';
	}

	var html = '<table class="paginationTable"><tr>';
	html += '<td class="results">Displaying '+parseInt(search_output['page_start'])+' - '+parseInt(search_output['page_end'])+' of '+parseInt(search_output['abs_total'])+'</td>';
	html += '<td class="pageNav">';

	var pagination_links = new Array();

	for (var i = 1; i <= page_total; i++)
	{
		if (i == current_page)
		{
			pagination_links.push('['+i+']');
		}
		else
		{
			pagination_links.push('<a href="#" onclick="'+pagination_function_name+'('+i+');">'+i+'</a>');
		}
	}

	html += pagination_links.join(' ');
	html += '</td>'
	html += '<td class="nextPrev">';

	var prev_next = new Array();

	if (current_page > 1)
	{
		prev_next.push('<a href="#" onclick="'+pagination_function_name+'('+(current_page - 1)+');">Prev</a>');
	}

	if (current_page < page_total)
	{
		prev_next.push('<a href="#" onclick="'+pagination_function_name+'('+(current_page + 1)+');">Next</a>');
	}

	html += prev_next.join(' | ');

	html += '</td>';
	html += '</tr></table>';

	return html;
}

/*
The Search_Options_Manager runs an iterative search and broadcasts
one type of metadata and the returned object list.
*/

Search_Options_Manager = function(params)
{
	if (params)
	{
		var search_results_handler = params['search_results_handler'];

		if (search_results_handler)
		{
			this.search_results_handler = search_results_handler;
		}
		else
		{
			this.search_results_handler = new Search_Results_Handler();
		}

		this.option_pkey = params['option_pkey'];
	}

	this.optionsUpdate = new YAHOO.util.CustomEvent('optionsUpdate');
	this.resultsUpdate = new YAHOO.util.CustomEvent('resultsUpdate');
}

Search_Options_Manager.prototype.setSearchStepFromSelect = function(select_obj)
{
	var split_id = select_obj.id.split('_');
	var step = split_id.pop();
	var selections = [];

	for (var i = 0; i < select_obj.options.length; i++)
	{
		if (select_obj.options[i].selected && !(select_obj.options[i].disabled))
		{
			selections.push(select_obj.options[i].value);
		}
	}

	this.search_results_handler.search_params_handler.setSearchParam(this.option_pkey, selections, step);
}

/*
triggerSelectionUpdate

* Input: event, Search_Options_Manager

Updates the Search_Options_Manager from the current select box
and runs its search for option data.

*/

triggerSelectionUpdate = function(e, obj)
{
	obj.setSearchStepFromSelect(this);
	obj.search_results_handler.requestResults();
}

/*
updateOptionsManager

* Input: Yahoo AJAX callback input with Search_Options_Manager in
argument[0]

Broadcasts search results data: object ID's and the option metadata
type set up in the Search_Options_Manager.

*/

updateOptionsManager = function(o)
{
	var search_options_manager = o.argument[0];
	var search_output = eval("(" + o.responseText + ")");

	search_options_manager.optionsUpdate.fire(search_options_manager.option_pkey, search_output[search_options_manager.option_pkey]);
	search_options_manager.resultsUpdate.fire(search_output['table_pkey'], search_output[search_output['table_pkey']]);
}

/*
updateSelectOptions

* Input: event name, [object_type, object_id_list], select box

Enables options found in the list.  Disables options not found
in the list.
*/

updateSelectOptions = function(event, args, obj)
{
	var option_list = args[1];

	for (var i = 0; i < obj.options.length; i++)
	{
		var option = obj.options[i];
		var result = option_list.binarySearch(option.value);

		if (option_list.binarySearch(parseInt(option.value)) >= 0)
		{
			option.disabled = false;
			option.className = 'active';
		}
		else
		{
			option.disabled = true;
			option.className = 'disabled';
		}
	}
}

/*
updateResultsDisplayHandler

* Input: event name, [object_type, object_id_list], Search_Results_Handler

Updates the Search_Params_Handler search criteria and sends a request
that will ultimately update the results count if the corresponding
container is set up.
*/

updateResultsDisplayHandler = function(event, args, obj)
{
	var object_type = args[0];
	var object_id_list = args[1];

	obj.search_params_handler.setSearchParam(object_type, object_id_list);
	obj.search_params_handler.setResultParam('full_results', 0);
	obj.requestResults();
}

connectUnorderedSearchSelects = function(params)
{
	var container = params['container'];
	var search_options_manager = params['search_options_manager'];

	if (!container || !search_options_manager)
	{
		return false;
	}

	var select_list = container.getElementsByTagName('select');
	for (var i = 0; i < select_list.length; i++)
	{
		var select_obj = select_list[i];
		YAHOO.util.Event.addListener(select_obj, 'change', triggerSelectionUpdate, search_options_manager);
		search_options_manager.optionsUpdate.subscribe(updateSelectOptions, select_obj);
	}

	search_options_manager.search_results_handler.requestResults();
}

/*
setupUnorderedSearch

* Input: a data structure of parameters
* Output: a reference to a function to show a given page of results

This sets up all the data handling objects and events of an unordered search
interface.  The event setup works like so:

Clicking on a search-related select box sends its selections to the
Search_Options_Manager.

The Search_Options_Manager finds the matching objects and the options
applicable to those objects.  It then broadcasts the object ID's and
option ID's.

Search-related select boxes receive the option ID list.  They disable
options not found in the list and enable options found in the list.

The display Search_Results_Handler receives the object ID list.  It
uses the list to update the results count and its search criteria.

Example of setup params structure:

var search_setup_params =
{
	option_search:
	{
		url: 'http://dev.conduit-it.com/cms/esab/dev/site/us/EN/home/filler_metals_catalog/filler_metals_guided_search',
		action: 'search_results',
		catalog_id: 'Filler_Metals',
		search_type: 'product_category',
		search_type_pkey: 'category_id',
		option_metadata: 'classif_id'
	},

	display_search:
	{
		url: 'http://dev.conduit-it.com/cms/esab/dev/site/us/EN/home/filler_metals_catalog/filler_metals_guided_search',
		action: 'search_results',
		search_type: 'product',
		search_type_pkey: 'product_id',
		page_max: 15,
		lib_cont_schema_id: 203,
		library_container_field: {"description":"short_desc","image":"web_small"},
		sitemap_node_id_list: {"product":1410,"product_category":1409},
		language_id: 1
	},

	display:
	{
		search_select_container_id: 'unordered_search_container',
		results_container_id: 'search_results_container',
		pagination_container_id: 'search_pagination_container',
		view_all_button_id: '',
		hide_all_button_id: '',
		pagination_function_name: 'showPage',
		result_count_container_id: 'result_count_container',
		animate_results: 1
	}
};

*/

setupUnorderedSearch = function(search_setup_params)
{
	var option_search_setup = search_setup_params.option_search;

	var option_params_handler = new Search_Params_Handler();

	option_params_handler.setResultParam('metadata', [option_search_setup.search_type_pkey, option_search_setup.option_metadata]);
	option_params_handler.setSearchParam('catalog_id', option_search_setup.catalog_id);
	option_params_handler.setSearchType(option_search_setup.search_type);

	var option_results_handler = new Search_Results_Handler( { search_params_handler: option_params_handler, url: option_search_setup.url, action: option_search_setup.action} );

	var search_options_manager = new Search_Options_Manager( { option_pkey: option_search_setup.option_metadata, search_results_handler: option_results_handler } );
	option_results_handler.setCallback( { success: updateOptionsManager, argument: [search_options_manager] } );

	var display_search_setup = search_setup_params.display_search;

	var display_params_handler = new Search_Params_Handler();

	display_params_handler.setLibraryContainerSchema(display_search_setup.lib_cont_schema_id);
	display_params_handler.setLibraryContainerField(display_search_setup.library_container_field);
	display_params_handler.setSitemapNode(display_search_setup.sitemap_node_id_list);
	display_params_handler.setLanguage(display_search_setup.language_id);
	display_params_handler.setSearchType(display_search_setup.search_type);
	display_params_handler.setResultParam('metadata', [display_search_setup.search_type_pkey]);
	display_params_handler.setPageMax(display_search_setup.page_max);

	var display_setup = search_setup_params.display;

	var display_results_handler = new Search_Results_Handler( { search_params_handler: display_params_handler, url: display_search_setup.url, action: display_search_setup.action} );

	display_results_handler.setCallback( { success: displaySearchResults, argument: [{ results_container: YAHOO.util.Dom.get(display_setup.results_container_id), pagination_container: YAHOO.util.Dom.get(display_setup.pagination_container_id), result_count_container: YAHOO.util.Dom.get(display_setup.result_count_container_id), view_all_button: YAHOO.util.Dom.get(display_setup.view_all_button_id), hide_all_button: YAHOO.util.Dom.get(display_setup.hide_all_button_id), pagination_function_name: display_setup.pagination_function_name, animate_results: display_setup.animate_results, auto_redirect: 1 }]} );

	search_options_manager.resultsUpdate.subscribe(updateResultsDisplayHandler, display_results_handler);

	YAHOO.util.Event.onContentReady(display_setup.search_select_container_id, connectUnorderedSearchSelects, { container: YAHOO.util.Dom.get(display_setup.search_select_container_id), search_options_manager: search_options_manager });

	showPage = function(page)
	{
		display_results_handler.search_params_handler.setResultParam('full_results', 1);
		display_results_handler.showPage(page);
	}

	return showPage;
}