/* Dynamic Catalogue Page Sort/Filter Facility for Actinic.
 *
 * Author: GF (started 20 Oct 08)
 *
 * Uses client-side Javascript. This ISN'T CALLED UNTIL USER EXPLICITLY SORTS/FILTERS PAGE, so if their JS
 * is old/incompatible, turned off or unsupported they can still view the original page in default (non-)order.
 *
 * Works by looking at custom (non-standard!) attributes within <td> elements in catalogue section
 * and organising according to them.
 *
 * (Requires correct placement of tags in Act_ProductLineRight.html)
 */

var	SUMMARY_PREFIX = 'smy',
	MIN_PRICE = 0,
	MAX_PRICE = 99999,
	TD_SHOW = '',
	TD_UNSHOW = 'none';

function addLeadingZeroes(number, minLength) {
	var	result = number + "";

	while (result.length < minLength) {
		result = "0" + result;
	}

	return result;
}

function getAllSummaryElements_OLD()
{
	var	result = new Array();
	var	index, lastElm;

	index = 1;
	do {
		lastElm = document.getElementById(SUMMARY_PREFIX + addLeadingZeroes(index, 5));
		if (lastElm !== null) {
			result.push(lastElm);
		}
		index += 1;
	} while (lastElm !== null);

	return result;
}

function getAllSummaryElements(summaryPrefixString)
{
	var	tempElements = document.getElementsByTagName('td'),
		result = new Array();

	/* Fetch elements */
	for (var key = 0; key < tempElements.length; ++key) {
		var	elm = tempElements[key];

		if (elm != null) { 

			var	id = elm.id;

			var	tagName = String(elm.tagName),
				start = id ? id.substring(0, SUMMARY_PREFIX.length) : "";

			if ((tagName.toUpperCase() == "TD") &&  (start == SUMMARY_PREFIX)) {
				result.push(elm);	
			} 
		}
	}

	/* Fetch prices (once only) and dynamically create attributes */
	for (key in result) {
		var	elm = result[key];
		var	price;

		if (elm.getAttribute('varprice') === null) {
			var	newAttrib;

			price = findPrice(result[key]);

			//newAttrib = document.createAttribute("varprice");
			elm.setAttribute("varprice", price);
			//alert('!');	/******GFTEST*/
		} 
	}

	return result;
}

/* Given elements in 'elms' (should be <td>s), this removes them from the document, and removes their immediate parent elements (should be <tr>) as well */
function removeAllElementsAndTheirParents(elms)
{
	var	parents = new Array();

	/* Remove child elements and note their parents */
	for (key in elms) {
		var elm = elms[key],
		    parent = elm.parentNode;

		if (parent !== null) {
			parents.push(parent);
			parent.removeChild(elm);			
		}
	}

	/* Now remove the parent elements */
	for (key in parents) {
		var parent = parents[key],
		    grandParent = parent.parentNode;

		if (grandParent != null) {
			grandParent.removeChild(parent);
		}
	}
}

/* Given a group of summary elements (which should be <td>s), this creates a set of new <tr> rows and adds those in turn to the 
 * specified grandparent node (which will likely be a <tbody> or a <table> itself 
 * grandParent: grandparent node (duh!)
 * rowSize: The number of summary elements to appear in each row (at time of writing, expect this to normally be 3)
 * tdElms: Node objects representing <td> elements in document
 */
function addNewRowsToGrandparent(grandParent, rowSize, tdElms)
{
	var	trs = new Array(),
		curTr,
		count;

	/* Create new <tr> elements and fill them up as necessary */
	count = 0;
	curTr = document.createElement('tr');
	for (tdKey in tdElms) {
		curTr.appendChild(tdElms[tdKey]);	
		if (tdElms[tdKey].style.display != TD_UNSHOW) {
			if (++count == rowSize) {			/* If <tr> full, add to grandparent and create new empty one */
				grandParent.appendChild(curTr);
				curTr = document.createElement('tr'); 
				count = 0;
			}
		}
		//alert('WHILE ADDING, LENGTH IS NOW {' + getAllSummaryElements().length + '}');	/******GFTEST*/
	}

	grandParent.appendChild(curTr);	
}

function sort()
{
	var	elms, parents, grandParent, minPriceFilter, maxPriceFilter;

	getAllSummaryElements();
	elms = getAllSummaryElements();

	if (elms.length == 0) {
		return;
	}

	grandParent = elms[0].parentNode.parentNode;
	removeAllElementsAndTheirParents(elms);

	/* Sort by specified method */

	var sortFn;
	switch (getSortByType()) {
		case 'packprice_asc':
			elms.sort(comparePriceAttribAsc);
			break;
		case 'packprice_desc':
			elms.sort(comparePriceAttribDesc);
			break;
		case 'unitprice_asc':
			elms.sort(comparePricePerUnitAsc);
			break;
		case 'unitprice_desc':
			elms.sort(comparePricePerUnitDesc);
			break;
		case 'packsize_asc':
			elms.sort(comparePacksizeAttribAsc);
			break;
		case 'packsize_desc':
			elms.sort(comparePacksizeAttribDesc);
			break;
		case 'brand_asc':
			elms.sort(compareBrandAttribAsc);
			break;
		case 'brand_desc':
			elms.sort(compareBrandAttribDesc);
			break;
		case 'rating_desc':
			elms.sort(compareRatingDesc);
			break;
		case 'rating_asc':
			elms.sort(compareRatingAsc);
			break;
		case 'none':
			// No sort
			break;
		default:
			alert("Sort type '" + getSortByType() + "' not supported");
			break;
	}

	/* Filter */
	resetSummaryDisplayStatus(elms);
	minPriceFilter = getPriceFilter(true);
	maxPriceFilter = getPriceFilter(false);
	if (minPriceFilter > maxPriceFilter) {
		var	temp = minPriceFilter;
		minPriceFilter = maxPriceFilter;
		maxPriceFilter = temp;
	}
	filterElements(elms, 'price', minPriceFilter, maxPriceFilter);
	filterElements(elms, 'brand', getBrandFilter());
	addNewRowsToGrandparent(grandParent, 3, elms);
}

/* Does standard ASCII string compare on (non-standard) varbrand attribute, for use with sort() */
function compareBrandAttribAsc(a, b)
{
	return strCompare(getFilteredVarbrand(a), getFilteredVarbrand(b));
}

function compareBrandAttribDesc(a, b)
{
	return strCompare(getFilteredVarbrand(b), getFilteredVarbrand(a));
}

function comparePriceAttribAsc(a, b)
{
	return parseFloat(a.getAttribute('varprice')) - parseFloat(b.getAttribute('varprice'));
}

function comparePriceAttribDesc(a, b)
{
	return parseFloat(b.getAttribute('varprice')) - parseFloat(a.getAttribute('varprice'));
}

function comparePacksizeAttribAsc(a, b)
{
	return getFilteredVarpacksize(a) - getFilteredVarpacksize(b);
}

function comparePacksizeAttribDesc(a, b)
{
	return getFilteredVarpacksize(b) - getFilteredVarpacksize(a);
}

function comparePricePerUnitAsc(a, b)
{
	return getFilteredPricePerUnit(a) - getFilteredPricePerUnit(b);
}

function comparePricePerUnitDesc(a, b)
{
	return getFilteredPricePerUnit(b) - getFilteredPricePerUnit(a);
}

function compareRatingDesc(a, b)
{
	var	ra = getRating(a, -1),
		rb = getRating(b, -1),
		result = ra - rb;

	return -result;
}


function compareRatingAsc(a, b)
{
	var	ra = getRating(a, 99999),
		rb = getRating(b, 99999),
		result = ra - rb;

	return result;
}

/* Given a (summary <td>) element), fetches the nonstandard varbrand attrib and filters empty/nonexistent values accordingly */
function getFilteredVarbrand(elm)
{
	var	brand = elm.getAttribute('varbrand');

	if ((brand === null) || (brand == ""))
		brand = "ZZZZ";			

	brand = brand.toLowerCase();

	return brand;
}

function getRating(elm, nonExistValue)
{
	var	productCode = elm.id.replace("smy", ""),
		price = rstars[productCode];
	
	if (typeof(price) == 'undefined') {
		return nonExistValue;
	} else {
		return parseFloat(price);
	}
}

/* function ALTgetRating(elm, nonExistValue)
{
	var	starId = elm.id.replace("smy", "starid");
	var	starElm = document.getElementById(starId);

		alert(document.getElementById('staridAU-GEEK036'));
	alert(starId + "/" + starElm);

	if (starElm !== null) {
		var	result = parseFloat(starElm.getAttribute('rating'));
		alert("found result, is " + result);
		return	isNaN(result) ? nonExistValue : result;
	} else {
		return nonExistValue;
	}
} */

function getFilteredVarpacksize(elm)
{
	var	packsize = elm.getAttribute('varpacksize');

	packsize = parseInt(packsize);
	packsize = isNaN(packsize) ? 1 : packsize;

	return packsize;
}

function getFilteredPricePerUnit(elm)
{
	var	packsize = getFilteredVarpacksize(elm);
	var	price = parseFloat(elm.getAttribute('varprice'));

	return price / packsize;
}

/* Horrible kludge to get price; because Actinic doesn't seem to give price as a *plain* NETQUOTEVAR we basically end up
 * 'scraping' the value by doing a search/regexp on the innerHTML. 
 * If there are two or more prices (e.g. logged in user gets normal price and their price), it selects the final one.
 * This function should only be used for sorting and filtering purposes (indirect convenience).
 */
function findPrice(elm)
{
	var	re = /\<b\>\&\#163;(.*)\<\/b\>/ig;
	var	re = /£(.*)<\/b>/ig;
	var	values, price;
	var	matchStr = elm.innerHTML;

	matchStr = matchStr.replace(/,/g, "");

	price = null;
	while ((values = re.exec(matchStr)) && (re.lastIndex > 0)) {
		price = values[1];
	}
	price = parseFloat(price);
	price = isNaN(price) ? MAX_PRICE : price;

	return price;
}

/* Given two strings, returns -1 if a < b, 0 if a == b or +1 if a > b */ 
function strCompare(a, b) 
{
	if (a < b) {
		return -1;
	} else if (a > b) {
		return +1;
	} else {
		return 0;
	}
}

/* Used to unfilter all elements to default display state (before user search), i.e. all showing */
function resetSummaryDisplayStatus(elms)
{
	for (key in elms) {
		elms[key].style.display = TD_SHOW;
	}
}

/* Selectively removes elements if AND ONLY IF the user has explicitly filtered search result (default page has them all showing) */
function filterElements(elms, funcString, param1, param2)
{
	funcString = funcString.toLowerCase() + "";

	for (key in elms) {
		var	match;

		switch (funcString) {
			case 'price':
				match = filterPrice(elms[key], param1, param2);
				break;
			case 'brand':
				match = filterBrand(elms[key], param1);
				break;
			default:
				match = true;
				alert('CANNOT FILTER ON "' + funcString + '"');
		}

		//elms[key].style.display = match ? TD_SHOW : TD_UNSHOW;
		elms[key].style.display = match ? elms[key].style.display : TD_UNSHOW;
	}
}

function TEST_filterFunction(elm)
{
	return true;
}

function filterPrice(elm, minPrice, maxPrice)
{
	var	price = findPrice(elm),
		result;

	result = ((price >= minPrice)  &&  (price <= maxPrice));
	return result;
}

function filterBrand(elm, matchStr)
{
	var	brand = getFilteredVarbrand(elm);

	matchStr = matchStr.toLowerCase();
	brand = brand.toLowerCase();

	matchStr = matchStr.replace(/[^0-9a-z]+/g, " ");
	matchStr = matchStr.replace(/^\s+/g, "");
	matchStr = matchStr.replace(/\s+$/g, "");
	brand = brand.replace(/[^0-9a-z]+/g, " ");
	brand = brand.replace(/^\s+/g, "");
	brand = brand.replace(/\s+$/g, "");

	return (brand.indexOf(matchStr) >= 0);
}

function sortByClickHandler(event)
{
	var	srcElement = event.target ? event.target : event.srcElement,
		childOption = srcElement.options[srcElement.selectedIndex];

	var	value = childOption.value;

	if (value == 'none') {
		return;
	}

	/* If you reinstate this section,  it has to be fixed for IE6 first, as that doesn't produce the expected behaviour */
	//if (srcElement.options[0].value == 'none') {
		//var	selectedIndex = srcElement.selectedIndex;

		//srcElement.removeChild(srcElement.options[0]);
		//srcElement.selectedIndex = selectedIndex - 1;
	//}

	sort();
}

function getSortByType()
{
	var	sElm = document.getElementById('sortSelect');

	return sElm.options[sElm.selectedIndex].value;
}

function getBrandFilter()
{
	var	fElm = document.getElementById('brandFilter');
	var	value = fElm.value.toLowerCase();

	value = (value == 'none') ? '' : value;

	return value;
}

/* Get either the minimum (isMin == true) or maximum (isMin == false) price filters specified by user */
function getPriceFilter(isMin)
{
	var	elm = isMin ? document.getElementById('minprice') : document.getElementById('maxprice'),
		value = parseInt(elm.value);

	if (isNaN(value)) {
		value = isMin ? '0' : MAX_PRICE;
		if (isMin  ||  (elm.value != '')) {
			elm.value = isMin ? '' : value;
		}
	}

	return value;
}

/* Based upon function at http://javascript.about.com/library/bldom08.htm */
document.getElementsByClassName = function(cl) {
	var retnode = [];
	var myclass = new RegExp('\\b'+cl+'\\b');
	var elem = this.getElementsByTagName('*');
	for (var i = 0; i < elem.length; i++) {
		var classes = elem[i].className;
		if (myclass.test(classes)) retnode.push(elem[i]);
	}

	return retnode;
};

function ulHandler()
{
	document.getElementById('sortSelect').selectedIndex = 0;
	document.getElementById('brandFilter').value = '';
	document.getElementById('minprice').value = MIN_PRICE;
	document.getElementById('maxprice').value = MAX_PRICE;
}

function addUl()
{
	window.onbeforeunload = ulHandler;
}
