
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// GET ABSOLUTE POSITION FUNCTION

function getAbsPos (el)
{
	var curleft = curtop = 0;
	
	if (el.offsetParent)
	{
		do
		{
			curleft += el.offsetLeft;
			curtop += el.offsetTop;
		}
		while (el = el.offsetParent);
	}
	
	return [curleft, curtop];
}


//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// SET OPACITY FUNCTION

function setOpacity (el, value)
{
	el.style.opacity = value / 100;
	el.style.filter = 'alpha(opacity=' + value + ')';
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// ARRAY TO STRING FUNCTION

function array_to_string (ARR)
{
	if (!ARR) {alert ('ARRAY TO STRING ERROR: Variable is empty.'); return '';}
	else if (!isArray (ARR) && returnOut) return '';
	else if (!isArray (ARR))  {alert ('ARRAY TO STRING ERROR: Variable is not an array.'); return '';}

	var OUT = "[";
	var justOpened = true;
	for (var idx in ARR)
	{
		if (isArray (ARR[idx])) OUT += array_to_string (ARR[idx]);
		else OUT += (justOpened ? '' : '|') + idx + "=>" + ARR[idx];
		justOpened = false;
	}
	OUT += "]";
	
	return OUT;
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// ARRAY SIGNATURE FUNCTION

function array_signature (ARR)
{
	return string_signature (array_to_string (ARR));
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// STRING SIGNATURE FUNCTION

/*
	This method will return a numeric signature of the character string. This number should be unique for any string taken the string
	contains only unicode characters within the 0-255 unicode range. In other words, as long as they contain the proper unicode characters
	different strings, nomatter how small the difference is, will always return different numbers.
*/

function string_signature (str)
{
	str = str + '';
	var sign = 0;
	for (i = 0; i < str.length; i ++) sign += (i * 255 + i) + str.charCodeAt (i);
	return sign;
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// PRINT STRING FUNCTION

function printstr (strVal, newWin)
{
	var winname = 'Print ' + (newWin ? Math.random () : '');
	winname = winname.replace (/[^a-zA-Z0-9]/g, '');
	
	var printrwin = window.open ('',winname,'height=400,width=500,scrollbars=1');
	var pwin = printrwin.document;
	pwin.write ('<html><head><title>PrintArray</title><style>body{font-family:verdana;font-size:12px;color:#444444;}</style></head><body>');
	pwin.write (strVal);
	pwin.write ('</body></html>');
	pwin.close ();
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// PRINT ARRAY WINDOW FUNCTION

function printrw (ARR, txtmode, returnOut, subCallLevel)
{
	printr (ARR, txtmode, returnOut, subCallLevel, true);
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// PRINT ARRAY FUNCTION

function printr (ARR, txtmode, returnOut, subCallLevel, winmode)
{
	if (!ARR) {alert ('PRINTR ERROR: Variable is empty.'); return '';}
	else if (!isArray (ARR) && returnOut) return '';
	else if (!isArray (ARR))  {alert ('PRINTR ERROR: Variable is not an array.'); return '';}

	var nlEl = txtmode ? "\n" : '<br>';
	var arrowEl = txtmode ? "=>" : '=&gt;';
	var identEl = txtmode ? '     ' : '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
	var level = (subCallLevel > 0) ? parseInt (subCallLevel) : 1;
	var ident = charString (identEl, level);
	
	var OUT = (subCallLevel > 0) ? '' : 'Array' +  nlEl + '(' + nlEl;
	for (var idx in ARR)
	{
		if (isArray (ARR[idx]))
		{
			OUT += ident + '[' + idx + '] ' + arrowEl + ' Array' + nlEl + ident + '(' + nlEl;
			OUT += printr (ARR[idx], txtmode, true, (level + 1));
			OUT += ident + ')' + nlEl;
		}
		else
		{
			OUT += ident + '[' + idx + ']' + arrowEl + ' ' + ARR[idx] + nlEl;
		}
	}
	
	if (!(subCallLevel > 0)) OUT += ")" + nlEl;
	
	if (returnOut) return OUT;
	else
	{
		var winname = 'PrintArray' + (winmode ? '' : Math.random ());
		winname = winname.replace (/[^a-zA-Z0-9]/g, '');
		
		var printrwin = window.open ('', winname, 'height=600,width=400,scrollbars=1');
		var pwin = printrwin.document;
		pwin.write ('<html><head><title>PrintArray</title><style>body{font-family:verdana;font-size:12px;color:#444444;}</style></head><body>');
		pwin.write (OUT);
		pwin.write ('</body></html>');
		pwin.close ();
	}
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// IS ARRAY FUNCTION

function isArray (obj)
{
	if (!obj || !obj.constructor) return false;
	else if (obj.constructor.toString ().indexOf ("Array") == -1) return false;
	else return true;
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// IS STRING FUNCTION

function isString (obj)
{
	if (obj && typeof obj == "string") return true;
	else return false;
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// CHAR STRING FUNCTION

function charString (chr, size)
{
	size = size ? size : 0;
	size = parseInt (size);
	var str = '';
	for (var i = 0; i < size; i ++) str += chr;
	return str;
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// HEX TO BIN FUNCTION

function hex2bin (hex, toArray)
{
	var bin = '0000';
	if (hex == '0' || hex == 0) bin = '0000';
	else if (hex == '1' || hex == 1) bin = '0001';
	else if (hex == '2' || hex == 2) bin = '0010';
	else if (hex == '3' || hex == 3) bin = '0011';
	else if (hex == '4' || hex == 4) bin = '0100';
	else if (hex == '5' || hex == 5) bin = '0101';
	else if (hex == '6' || hex == 6) bin = '0110';
	else if (hex == '7' || hex == 7) bin = '0111';
	else if (hex == '8' || hex == 8) bin = '1000';
	else if (hex == '9' || hex == 9) bin = '1001';
	else if (hex == 'A') bin = '1010';
	else if (hex == 'B') bin = '1011';
	else if (hex == 'C') bin = '1100';
	else if (hex == 'D') bin = '1101';
	else if (hex == 'E') bin = '1110';
	else if (hex == 'F') bin = '1111';
	
	if (toArray)
	{
		bin = bin.split ('');
		return [parseInt (bin[0]), parseInt (bin[1]), parseInt (bin[2]), parseInt (bin[3])];
	}
	else return bin;
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// BIN TO HEX FUNCTION

function bin2hex (bin)
{
	switch (bin)
	{
		case '0000': return '0';
		case '0001': return '1';
		case '0010': return '2';
		case '0011': return '3';
		case '0100': return '4';
		case '0101': return '5';
		case '0110': return '6';
		case '0111': return '7';
		case '1000': return '8';
		case '1001': return '9';
		case '1010': return 'A';
		case '1011': return 'B';
		case '1100': return 'C';
		case '1101': return 'D';
		case '1110': return 'E';
		case '1111': return 'F';
		default: return '0';
	}
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// LIST CHECK CLICK FUNCTION

function list_check_click ()
{
	var lc = document.getElementById ('list_check');
	var el = document.getElementsByTagName ("input");
	for (idx = 0; idx < el.length; idx ++)
	{
		if (el[idx].id.match (/^checkbox_/)) el[idx].checked = lc.checked;
	}
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// SET DEFAULT SELECT FUNCTION

function set_def_select (sel_id, sel_val)
{
	var sel_el = document.getElementById(sel_id);
	for (i=0; i < sel_el.options.length; i++)
	{
		if (sel_el.options[i].value == sel_val)
		{
			sel_el.selectedIndex = i;
		}
	}
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// SET DEFAULT MULTISELECT FUNCTION

function set_def_multiselect (sel_id, sel_values)
{
	if (!sel_values) return false;

	var values = sel_values.split (',');
	
	var sel_el = document.getElementById (sel_id);
	for (i=0; i < sel_el.options.length; i++)
	{
		if (in_array (sel_el.options[i].value, values))
		{
			sel_el.options[i].selected = true;
		}
	}
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// IN ARRAY FUNCTION

function in_array (value, arr)
{
    for (var i = 0; i < arr.length; i ++)
	{
        if (arr[i] == value) return true;
    }
    return false;
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// URL FUNCTION

function url (module, page, params)
{
	if (!url_path) 
	{
		alert("Redirection error: url_path not set");
		return false;
	}

	var url_form = "{url_path}/index.php?request:{module}-{page}{&{param}={value}}";
	var url_addr = url_form;
	var param_block = "";
	var param_block_form = null;
	
	// replace url_path
	url_addr = url_addr.replace(/\{url_path\}/, url_path);
	
	// replace module
	url_addr = url_addr.replace(/\{module\}/, module);
	
	// replace page
	url_addr = url_addr.replace(/\{page\}/, page);
	
	// get param block
	var re = new RegExp(/\{[^\{\}]?\{(param|value)\}[^\{\}]?\{(param|value)\}[^\{\}]?\}/);
	var m = re.exec(url_addr);
	if (m == null)
	{
		alert("Redirection error: url_form could not be processed");
		return false;
	}
	else
	{
		param_block_form = m[0];
    }
	
	// extract params
	if (params)
	{
		var PRM = new Array();
		PRM = params.split("&");
		
		// replace params
		for (i = 0; i < PRM.length; i++)
		{
			var aux = PRM[i].split("=");
			block = param_block_form.replace(/\{param\}/, aux[0]).replace(/\{value\}/, aux[1]);
			block = block.substr(1, block.length - 2);
			param_block += block;
		}
	}
	
	// prep for substitution (escape regexp special chars)
	param_block_form_re = param_block_form.replace(/([^a-zA-Z0-9 _><=])/g, "\\$1");
	
	// replace param block
	url_addr = url_addr.replace(eval("/" + param_block_form_re + "/"), param_block);
	
	return url_addr;
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// TOGGLE TEXTBOX EXPAND FUNCTION

function toggle_textbox_expand (el)
{
	if (el.parentNode.tagName == 'DIV')
	{
		if (!el.isexp || el.isexp == false)
		{
			el.innerHTML = '-';
			el.parentNode.className = 'lst_txt_cont_exp';
			el.isexp = true;
		}
		else
		{
			el.innerHTML = '+';
			el.parentNode.className = 'lst_txt_cont';
			el.isexp = false;
		}
	}
	else alert ('Text box expansion failed.');
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// REROUTE HTML LINKS FUNCTION

function reroute_html_links (htm, callback_function_name)
{
	// route all anchors with onclick events through our callback function, the original content of the onlick, if any, will be passed as a function to our callback
	htm = htm.replace (/<a (.*?)onclick\s*=\s*"(.*?)"(.*?)>/gi, '<TMPANCHOR $1onclick="return ' + callback_function_name +  ' (this, function () { $2 });"$3>');
	
	// add onlick events with routing through our callback to all anchors that do not have onclick events originally set
	htm = htm.replace (/<a (.*?)>/gi, '<a $1 onclick="return ' + callback_function_name +  ' (this, null);">');
	
	// revert all temp anchors to anchor value
	htm = htm.replace (/<TMPANCHOR (.*?)>/gi, '<a $1>');
	
	// return processed html
	return htm;
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// REROUTE HTML FORMS FUNCTION

function reroute_html_forms (htm, callback_function_name)
{
	// route all forms with onsubmit events through our callback function, the original content of the onsubmit, if any, will be passed as a function to our callback
	htm = htm.replace (/<form (.*?)onsubmit\s*=\s*"(.*?)"(.*?)>/gi, '<TMPFORM $1onsubmit="return ' + callback_function_name +  ' (this, function () { $2 });"$3>');
	
	// add onsubmit events with routing through our callback to all forms that do not have onsubmit events originally set
	htm = htm.replace (/<form (.*?)>/gi, '<form $1 onsubmit="return ' + callback_function_name +  ' (this, null);">');
	
	// revert all temp forms to form value
	htm = htm.replace (/<TMPFORM (.*?)>/gi, '<form $1>');
	
	// return processed html
	return htm;
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// FORMS HTML TO REMOTE FUNCTION

/*
	This method will convert all html forms within the htm parameter (which contains html) to 
	remotely processed forms (which get resolved through the httpBus class). The HTB parameter
	should be a configured instance of the httpBus object, callback function to be triggered
	when the form processing result is returned by the server will be the callback set within
	the HTB object.
	
	Note that due to the impossibility of predicting the URL format accepted by the server-side
	application, remote forms will only work in POST mode, even if the form has its method set
	to GET.
*/

var remoteFormsHTTPBus = null;
function forms_html_to_remote (htm, HTB)
{
	// store HTB
	remoteFormsHTTPBus = HTB;

	// convert html forms to remote forms (onsubmit remote_form_submit will be called)
	return reroute_html_forms (htm, 'remote_form_submit');
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// GET FORM INFORMATION FUNCTION

function remote_form_submit (frm, onsbmt)
{
	// set continue flag
	var cont = true;
	
	// execute original link onsubmit
	if (onsbmt)
	{
		// capture outcome
		var onsbmt_outcome = onsbmt ();
		
		// if outcome is not null determine if we should continue with the remote post or not based on the outcome (this should make client-side validations on forms work in remote mode too)
		if (onsbmt_outcome != null) cont = onsbmt_outcome ? true : false;
	}
	
	// if we are clear to continue
	if (cont)
	{
		// get form information
		var FRM_INFO = get_form_information (frm);
		
		// post form through http bus
		remoteFormsHTTPBus.postURL (FRM_INFO['action'], FRM_INFO['FIELDS']);
	}
	
	// prevent form from getting submitted
	return false;
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// GET FORM INFORMATION FUNCTION

function get_form_information (frm)
{
	var DATA = new Array ();
    if (frm)
	{
		// get general form properties
		DATA['id'] = frm.id;
		DATA['name'] = frm.name;
		DATA['action'] = frm.action;
		DATA['method'] = frm.method;
		DATA['FIELDS'] = new Array ();
		
		// extract list of fields that have values
		var FIELDS = get_form_fields (frm);
		if (FIELDS.length)
		{
			for (var idx = 0; idx < FIELDS.length; idx ++)
			{
				if (FIELDS[idx].type == 'text' || FIELDS[idx].type == 'hidden' || FIELDS[idx].type == 'password')
				{
					DATA['FIELDS'][FIELDS[idx].name] = FIELDS[idx].value;
				}
				else if (FIELDS[idx].type == 'select-one' && FIELDS[idx].options && FIELDS[idx].options.length)
				{
					DATA['FIELDS'][FIELDS[idx].name] = FIELDS[idx].options[FIELDS[idx].selectedIndex].value;
				}
				else if (FIELDS[idx].type == 'select-multiple' && FIELDS[idx].options && FIELDS[idx].options.length)
				{
					DATA['FIELDS'][FIELDS[idx].name] = new Array ();
					for (var idxx = 0; idxx < FIELDS[idx].options.length; idxx ++)
						if (FIELDS[idx].options[idxx] && FIELDS[idx].options[idxx].selected)
							DATA['FIELDS'][FIELDS[idx].name].push (FIELDS[idx].options[idxx].value);
				}
				else if (FIELDS[idx].type == 'textarea')
				{
					DATA['FIELDS'][FIELDS[idx].name] = FIELDS[idx].value;
				}
				else if (FIELDS[idx].type == 'checkbox')
				{
					if (FIELDS[idx].checked) DATA['FIELDS'][FIELDS[idx].name] = FIELDS[idx].value;
				}
				else if (FIELDS[idx].type == 'radio')
				{
					if (FIELDS[idx].checked) DATA['FIELDS'][FIELDS[idx].name] = FIELDS[idx].value;
				}
			}
		}
	}
	
	return DATA;
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// GET FORM FIELDS FUNCTION

function get_form_fields (frm)
{
	var FIELDS = new Array ();
	
	if (frm)
	{
		var TYPES = ["input", "textarea", "select"];
		for (var idx in TYPES)
		{
			var LST = frm.getElementsByTagName (TYPES[idx]);
			for (var idxx = 0; idxx < LST.length; idxx ++) // somehow, using "var idxx in LST" approach will skip radio boxes in IE when more than 1 radio box input is defined
				if (LST[idxx] && LST[idxx].name && LST[idxx].name != undefined && LST[idxx].type && LST[idxx].type != undefined)
					FIELDS[FIELDS.length] = LST[idxx];
		}
	}
	
	return FIELDS;
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// PREG QUOTE FUNCTION

function preg_quote (str)
{
    return (str + '').replace (/([\/\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1");
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// BIND EVENT FUNCTION

function bindEvent (event, obj, callback, capturePhase)
{
	if (!obj) return false;
	capturePhase = capturePhase ? true : false;
	
	if (obj.addEventListener) obj.addEventListener (event, callback, capturePhase);
	else if (obj.attachEvent) obj.attachEvent ('on' + event, callback);
	else return false;
	
	return true;
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// CLEAR EVENT FUNCTION

function clearEvent (event, obj, callback, capturePhase)
{
	if (!obj) return false;
	capturePhase = capturePhase ? true : false;
	
	if (obj.removeEventListener) obj.removeEventListener (event, callback, capturePhase);
	else if (obj.detachEvent) obj.detachEvent ('on' + event, callback);
	else return false;
	
	return true;
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// TRIM FUNCTION

function trim (text)
{
	return text.replace (/^\s+|\s+$/g, '');
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// VALUE DEFAULT FUNCTION
	
/*
	Will return val if it has a value (including zeros) otherwise it will return def.
*/

function valDef (val, def)
{
	if (val === 0 || (val && val != undefined)) return val;
	else return def;
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// REPLACE NODE WITH HTML FUNCTION
	
/*
	This function is a bridge between DHTML and DOM, allowing the replacement of 
	a specific DOM node with any custom html block.
*/

function replaceNodeWithHTML (nodeRef, htm)
{
	// create virtual container and add our html to it
	var tmpDiv = document.createElement ('div');
	tmpDiv.innerHTML = htm;
	
	// create document fragment
	var docFrag = document.createDocumentFragment ();
	
	// walk all the nodes in our temp div and create them within the document fragment
	var currNode = tmpDiv.firstChild;
	while (currNode)
	{
		// clone current node
		var clone = currNode.cloneNode (true);
		
		// append clone to document fragment
		docFrag.appendChild (clone);
		
		// next node
		currNode = currNode.nextSibling;
	}
	
	// replace our node with the doc fragment we created
	nodeRef.parentNode.replaceChild (docFrag, nodeRef);
}

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// STOP EVENT PROPAGATION FUNCTION
	
function stop_event_propagation (e)
{
	if (!e) var e = window.event;
	e.cancelBubble = true;
	if (e.stopPropagation) e.stopPropagation();
}

function coupon_submit (frm)
{
	var err = '';
	
	var nameVal = frm.infrm_name.value;
	nameVal = nameVal.replace (/\s+/, ' ');
	nameVal = nameVal.replace(/^\s+|\s+$/g,"");
	
	if (!nameVal || nameVal == ' ') err += '    - you forgot to enter your full name\n';
	else if (!nameVal.match (/^.*? .*$/i)) err += '    - please enter your first name followed by your last name in the name field (e.g. Henry Jones)\n';
	else if (!(nameVal.length >= 3 && nameVal.length <= 20)) err += '    - name is too long, must be between 3 and 20 characters\n';
	
	if (!frm.infrm_email.value) err += '    - you forgot to enter your email address\n';
	else if (!frm.infrm_email.value.match (/^[A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4}$/i)) err += '    - detected invalid email address\n';
	else if (!(frm.infrm_email.value.length >= 5 && frm.infrm_email.value.length <= 50)) err += '    - email address must be between 5 and 50 characters long\n';
	
	//if (!frm.infrm_phone.value) err += '    - you forgot to enter your phone number\n';
	//else if (!frm.infrm_phone.value.match (/^[0-9]{3}-[0-9]{3}-[0-9]{4}$/)) err += '    - detected invalid phone number, please use the following phone format: XXX-XXX-XXXX \n';
	
	if (err) alert ('Oops, the form could not be submitted...\n' + err);
	else frm.submit ();
}


function coupon_unsub (frm)
{
	var err = '';
	
	if (!frm.infrm_email.value) err += '    - you forgot to enter your email address\n';
	else if (!frm.infrm_email.value.match (/^[A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4}$/i)) err += '    - detected invalid email address\n';
	else if (!(frm.infrm_email.value.length >= 5 && frm.infrm_email.value.length <= 50)) err += '    - email address must be between 5 and 50 characters long\n';
	
	if (err) alert ('Oops, the form could not be submitted...\n' + err);
	else frm.submit ();
}
