/*
	Intellectual property of Twig Interactive LLC
	Do not reuse or alter without express permission
	http://www.twiginteractive.com
*/

/* Twig Class */
var TWIG = {};

// Statics
TWIG.defaultTuringTestValue = 'Enter code...';
TWIG.defaultSearchValue = 'Enter keyword...';


/* General web functions */

// Get and format hash for bookmarks: strip pound symbol then decode
TWIG.getHash = (function() {							 
	function T() {
		return ((window.location.hash) ? URLDecode((window.location.hash.substring(1))) : ''); 
	}
		 
	return T;								 
})();

// Checks for the session-level cookie required for PHP work
TWIG.sessionSupportDetection = (function() {
	function T() {
		var sessionCookieValid = ((getCookie('TWIGSESHID') == null) ? false : true);
		if (sessionCookieValid == false) {
			// Twig session cookie not set - display warning
			$('#tpl_session-warning').show('fast');
			return false;
		};
		return true;
	}
	
	return T;
})();

// Obfuscate emails
// Requires parameters to be passed from PHP obfuscateEmail() fn
TWIG.obfusc = (function() {
	function T(add,dom,cc,bcc,subj,bdy) {
		var obfusced = ("mail" + "to" + unescape("%3A") + escape(add) + unescape("%40") + escape(dom));
		if (subj != '') { obfusced += (unescape("%3F") + "subject" + unescape("%3D") + escape(subj)); };
		if (cc != '') { obfusced += (unescape("%26") + "cc" + unescape("%3D") + escape(cc)); };
		if (bcc != '') { obfusced += (unescape("%26") + "bcc" + unescape("%3D") + escape(bcc)); };
		if (bdy != '') { obfusced += (unescape("%26") + "body" + unescape("%3D") + escape(bdy)); };
		window.location.href=obfusced;
		return false;
	}
	
	return T;
})();

// Used to set anchor targets for external links and pop-ups
TWIG.setExternalLinks = (function() {
	function T() {
		var anchors = $('a'); // Get <a> tags
		anchors.each(function(idx){
			var a = $(this);
			if (a.attr('rel') == 'external') {
				a.attr('target','_blank'); // Set target
			}
			else if (a.attr('rel') == 'popup') {
				// Prevent multiple application
				if (a.attr('href').match(/^javascript:/)) {
						return void(0);
				};

				var popupParams = "'"+a.attr('href')+"','POPUP'"; // Build pop-up params list
				if ($.trim(a.attr('rev')) != '') { popupParams += ","+a.attr('rev'); };
				a.attr('href','javascript:void(0);'); // Clear href entry to prevent parent location changing
				a.unbind('click.setExternalLinks').bind('click.setExternalLinks', function(evt) { // Bind the onclick event
					eval('TWIG.openWindow('+popupParams+');'); // Pass eval'd params to openWindow fn
					return void(0);
				});
			};
		});
	}
	
	return T;
})();

// Open a pop-up window with set parameters
TWIG.openWindow = (function() {
	function T(URL,Name,W,H,L,T,Scrolls,Resize) {
		// Used to control params of pop-ups
		var defProps = 'copyhistory=no,directories=no,fullscreen=no,location=no,menubar=no,status=no,titlebar=yes,toolbar=no';
		var poppedProps = '';
	
		if (W != null) {
			if (Scrolls == true) { W += 16; } // Allow for chrome in IE
			poppedProps += ('width='+W+',');
		}
		if (H != null) { poppedProps += ('height='+H+','); }
		if (L != null) { poppedProps += ('left='+L+','); }
		if (T != null) { poppedProps += ('top='+T+','); }
		poppedProps += 'scrollbars=' + ((Scrolls != false) ? 'yes' : 'no') + ',' ; // Default 1
		poppedProps += 'resizable=' + ((Resize != false) ? 'yes' : 'no') + ',' ; // Default 1
		poppedProps += defProps;

//		alert(poppedProps);		
		poppedUp = window.open(URL,Name,poppedProps);
		if (poppedUp) { setTimeout("poppedUp.window.focus();",100); };
		return poppedUp;
	}
	return T;
})();

// Toggles between default value and empty string
TWIG.toggleTextInputValue = (function() {
	function T(o,evt,defVal,len) {
		if (typeof(len) == 'undefined') {
			len = 60; // Default max length
		};
		if (evt == 'focus') {
			if ($.trim(o.value) == defVal) {
				o.maxLength = len;
				o.value = '';
			};
		};
		if (evt == 'blur') {
			if ($.trim(o.value) == '') {
				o.maxLength = defVal.length;
				o.value = defVal;
			};
		};
	}

	return T;
})();

// Checks email address against RFC rules
// Based on original PHP code by Cal Henderson (http://iamcal.com/publish/articles/php/parsing_email)
// Twig converted to JS regex
TWIG.isValidEmailAddress = (function() {
	function T(email) {
		var qtext = '[^\\x0d\\x22\\x5c\\x80-\\xff]';
		var dtext = '[^\\x0d\\x5b-\\x5d\\x80-\\xff]';
		var atom = '[^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c'+'\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+';
		var quoted_pair = '\\x5c\\x00-\\x7f';
		var domain_literal = '\\x5b('+dtext+'|'+quoted_pair+')*\\x5d';
		var quoted_string = '\\x22('+qtext+'|'+quoted_pair+')*\\x22';
		var domain_ref = atom;
		var sub_domain = '('+domain_ref+'|'+domain_literal+')';
		var word = '('+atom+'|'+quoted_string+')';
		var domain = sub_domain+'(\\x2e'+sub_domain+')*';
		var local_part = word+'(\\x2e'+word+')*';
		var addr_spec = local_part+'\\x40'+domain;
		var filter = eval('/^' + addr_spec + '$/');
		
		if (filter.test(email)) { // Passes RFC RegEx
			// Sanity check for period '.' following @
			if (email.indexOf('.',email.indexOf('@')) >= 0) {
				return true;
			}
		}
		return false;
	}
	
	return T;
})();

// Checks input against RegEx for valid website URL
TWIG.isValidURL = (function() {
	function T(URL) {
		var urlMatch = /^https?:\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
		if (urlMatch.test(URL)) { // Passes RegEx
			// Sanity check for period '.' following //
			if (URL.indexOf('.',URL.indexOf('//')) >= 0) {
				return true;	
			}
		}
		return false;
	}
	
	return T;
})();

// Checks input against known CC types
TWIG.isValidCCNumber = (function() {
	function T(cc) {
		
		function getdigits (s) {
			return s.replace (/[- ]/g, '');
		}

		function luhn (cc) {
			var sum = 0;
			var i;
			for (i = cc.length - 2; i >= 0; i -= 2) {
				sum += Array (0, 2, 4, 6, 8, 1, 3, 5, 7, 9) [parseInt (cc.charAt (i), 10)];
			};
			for (i = cc.length - 1; i >= 0; i -= 2) {
				sum += parseInt (cc.charAt (i), 10);
			};
			return (sum % 10) == 0;
		}

		var creditCardList = [
			//	Type						RegEx
			["VISA",						"4[0-9]{12}(?:[0-9]{3})?"],
			["MasterCard",				"5[1-5][0-9]{14}"],
			["AMEX",						"3[47][0-9]{13}"],
			["Discover",				"6(?:011|5[0-9]{2})[0-9]{12}"]
		];

		cc = getdigits(cc); // Strip spaces and hyphens
		if (luhn (cc)) { // Check against algorythm
			for (var i in creditCardList) { // Check against RegEx
				re = new RegExp("^"+creditCardList[i][1]+"$");
				if (cc.match(re) != null) {
					return creditCardList[i][0]; // Match found
				}
			};
		};
		return false;
	}
	
	return T;
})();

// Enforce maximum lengths on text input boxes and textareas, driven by attributes
// Assumes length given by either 'maxlength' or 'cols' attributes 
TWIG.limitInputLengths = (function() {
	function T() {
		var limitTextInputs = (function(evt) {
			var maxLength = ($(this).attr('cols') ? $(this).attr('cols') : $(this).attr('maxlength'));
			var inputLength = this.value.length;
	
			if (evt.type == 'keypress') { // Text added via keyboard
				var key = evt.which;
				if (!evt.ctrlKey && (key >= 32 || key == 13)) { // Allow deletion and CTRL shortcuts
					if (inputLength >= maxLength) {
						evt.preventDefault(); // Prevent addition
					};
				};
			}
			else if (evt.type == 'change') { // Text added via mouse
				if (inputLength >= maxLength) {
					$(this).val($(this).val().substr(0, maxLength)); // Crop
				};
			};
		});
		
		// Text and password inputs, but not Turing tests
		$('input[type="text"],input[type="password"]').not('.turingTest').unbind('keypress.limitInputLengths').bind('keypress.limitInputLengths', limitTextInputs);
		$('input[type="text"],input[type="password"]').not('.turingTest').unbind('change.limitInputLengths').bind('change.limitInputLengths', limitTextInputs);
		
		// Textarea inputs
		$('textarea').unbind('keypress.limitInputLengths').bind('keypress.limitInputLengths', limitTextInputs);
		$('textarea').unbind('change.limitInputLengths').bind('change.limitInputLengths', limitTextInputs);
	};

	return T;
})();

// Hooks STATE and COUNTRY dropdowns together for logical display
// Requires page form select elements FRM_state and FRM_country in the usual DOM structure
// Pass form prefix for each set of fields to hook
TWIG.hookStateAndCountryFields = (function() {
	function T(frm) {
		if ($('#'+frm+'_state,#'+frm+'_country').length == 0) { return false; };
		
		// State
		if ($('#'+frm+'_state').attr('selectedIndex') == $('#'+frm+'_state').attr('length')-1) {
			$('#'+frm+'_state').parent().parent().hide(); // Hide row if State = N/A
		};
		$('#'+frm+'_state').bind('change', function(evt) { // Match Country to State
			var state = $('option:selected', this);
			if (state.value.length > 0) {
				var country = state.parent().attr('label'); // Get country from optgroup
				if (country) {
					$('#'+frm+'_country option').each(function(n) {
						el = $(this);
						if (el.val() == country) {
							el.selectMe();
						};
					});
				}
				else {
					$('#'+frm+'_country').attr('selectedIndex',0); // Reset Country
				};
			};
		});
	
		// Country
		$('#'+frm+'_country').bind('change', function(evt) {
			var country = this[this.selectedIndex].value;
			if (country.length > 0) {
				if (country.match(/(\bUnited States of America\b)|(\bCanada\b)/i)) { // Country match
					if ($('#'+frm+'_state').attr('selectedIndex') == $('#'+frm+'_state').attr('length')-1) {
						$('#'+frm+'_state').attr('selectedIndex',0); // Reset State
					};
					$('#'+frm+'_state').parent().parent().show(); // Show State row
				}
				else { // No country match
					$('#'+frm+'_state').attr('selectedIndex',$('#'+frm+'_state').attr('length')-1); // Set State to N/A
					$('#'+frm+'_state').parent().parent().hide(); // Hide State row					
				};
			};
		});
		
	}

	return T;
})();

/* Form-field validation functions */
TWIG.validateInput_email = (function() {
	function T(el,evt) {
		el.value = $.trim(el.value.toLowerCase()); // Lowercase & trimmed
		var email = el.value;
		if ((email != '') && (!TWIG.isValidEmailAddress(email))) {
			// Format failure
			$(el).addClass('frmFieldError');
			alert('Please enter a valid email address.');
			return false;
		}
		else {
			$(el).removeClass('frmFieldError');
			return ((email == '') ? false : true);
		};
	}
	
	return T;
})();

TWIG.validateInput_password = (function() {
	function T(el,evt) {
		var pwd = el.value;
		if ((pwd != '') && (pwd.length < 6)) {
			// Length failure
			$(el).addClass('frmFieldError');
			alert('Your password must be at least 6 characters long.');
			return false;
		}
		else {
			$(el).removeClass('frmFieldError');
			return ((pwd == '') ? false : true);
		};	
	}
	
	return T;
})();

TWIG.validateInput_websiteURL = (function() {
	function T(el,evt) {
		el.value = $.trim(el.value.toLowerCase()); // Trim & lowercase
		var URL = el.value;
		
		// Test for protocol
		if ((URL != '') && (!URL.match(/^https?:\/\//))) {
			el.value = 'http://' + URL; // Update display
			URL = el.value; // Update for testing
		};

		// Test validity
		if ((URL != '') && (!TWIG.isValidURL(URL))) {
			// Match failure
			$(el).addClass('frmFieldError');
			alert('Please enter a valid website URL.');
			return false;
		}
		else {
			$(el).removeClass('frmFieldError');
			return ((URL == '') ? false : true);
		};
	}
	
	return T;
})();
					
TWIG.validateInput_ccNumber = (function() {
	function T(el,evt) {
		var cc = $.trim(el.value); // Trim
		if ((cc != '') && (!(ccType = TWIG.isValidCCNumber(cc)))) {
			// Format failure
			$(el).addClass('frmFieldError');
			alert('Please enter a valid credit card number.');
			return false;
		}
		else {
			// Either passed or empty
			$(el).removeClass('frmFieldError');
			return ((cc == '') ? false : ccType);
		};
	}
	
	return T;
})();

// Function to cache all images used in primary and secondary navigation
TWIG.cacheNavImages = (function() {
	function T() {
		var aNavImages = new Array();
		aNavImages.push(
		'/graphics/spacer.gif'
		);
		
		for(i in aNavImages) {
			eval["navImg"+i+"_cache"] = new Image();
			eval["navImg"+i+"_cache"].src = aNavImages[i];
		};

	}
	
	return T;
})();

/* General web functions */


// TabSet class: receives the div.tabset wrapped set
TWIG.TabSet = (function() {
	function T(el) {

		// Hide elements not required when JS is active
		$('.noJS', el).hide();
			
		// Get tabs from tabset
		var tabs = $('ul.tabs li.tab', el);
		var menuHeight = $('.menu', el).outerHeight();
		
		// Process each tab
		tabs.each(function(idx) {
			// Grab the identifier, the tab and the corresponding content
			// Identifier must be unique on the page for bookmarking to work
			var t = $(this);
			var tc = $('#' + t.attr('id').replace(/tab_/,'tab-content_')); // Simple RegEx
			var i = t.attr('id').replace(/tab_/,'');
			
			// Process anchor tags
			t.find('a').each(function(i) {
				// Replace hash in anchor with JS void
				$(this).attr('href', 'javascript:void(0);');
			});
			tc.find('a').each(function(i) {
				// Check for tab-relative bookmarks
				if ($(this).attr('rel') == 'tab') {
					$(this).unbind('click.tabSet').bind('click.tabSet', function(evt) {
						// Replicate corresponding li click
						$('li#tab_'+$(this).attr('href').replace(/#/,'')).click(); 
					});
				};
			});
			
			// Remove unnecessary bookmarks from tab content to prevent page jumping
			tc.find('a[name='+i+']').remove();

			// Set content height to at least match menu
			if (tc.outerHeight() < menuHeight) {
				// Get padded difference
				var padY = (tc.outerHeight() - tc.height());
				tc.height((menuHeight-padY)+'px');
			};
			
			// Get vertical offset
			var tabsetOffset = el.offset({ relativeTo: document });

			// Look for tab in hash
			if (global_pageBookmark.toLowerCase().indexOf(i.toLowerCase()) === 0) { // Tab found	
				// Turn other tabs 'off' & hide content
				tabs.filter('.on').removeClass('on');
				$('.tab-content', el).hide();
				$('.tab-content', el).removeClass('on');
				$('a.current', tabs).removeClass('current');
				
				// Turn this tab 'on'
				t.addClass('on');
				tc.addClass('on');
				tc.show();

				// Scroll to place tabset in view
				$(document).scrollTop(tabsetOffset['top']);

			}
			else { // Set initial view
				// Hide other tab contents
				$('.tab-content', el).not('.on').hide();
			};
			
			// Style selected tab's anchor as current
			if (t.attr('class').match(/\bon\b/)) {
				t.find('a').each(function(i) {
					$(this).addClass('current');
				});
			};
			
			// Bind the click event
			t.unbind('click.tabSet').bind('click.tabSet', function(evt) {

				// Grab the tab
				var li = $(this);
				
				// If tab is 'on', stop processing
				if (li.hasClass('on')) return;
				
				// Turn other tabs 'off' & hide content
				tabs.filter('.on').removeClass('on');
				$('.tab-content', el).hide();
				$('.tab-content', el).removeClass('on');
				$('a.current', tabs).removeClass('current');

				// Turn this tab 'on'
				li.addClass('on');
				tc.fadeIn(function() {
					$(this).fadeIn('fast');
					if ($.browser.msie) { this.style.removeAttribute('filter'); }; // IE ClearType fix
				 });
				tc.addClass('on');
				
				// Style anchor as current
				li.find('a').each(function(i) {
					$(this).addClass('current');
				});
				
				// Scroll to place tabset in view
				$(document).scrollTop(tabsetOffset['top']);

				// Set bookmark
				window.location.hash = i;
			});
		});
	}
	
	return T;
})();

// Function to stripe a <table> wrapped set
// Will remove any class 'zebra' and add 'zebra' class to alternating (even) rows
TWIG.StripeMe = (function() {
	function T(el) {
		el.each(function(n) {
			$(this).find('tr.zebra').each(function(o) {
				$(this).removeClass('zebra');
			})
			$(this).find('tr:odd').addClass('zebra');
		});
	}
	
	return T;
})();
		
		
// Function to display the tab containing the element in a wrapped set
TWIG.ShowMyTab = (function() {
	function T(el) {		
		// Cycle thru parents to find tab
		el.parents().each(function(n) {
			if (this.id.match(/^tab-content_/)) {
				// Found containing tab
				var li = $('#'+this.id.replace(/^tab-content_/, 'tab_'));
				li.click(); // Ensure tab is visible
			};
		});
	}
	
	return T;
})();


// Function to create and show processing mask
TWIG.showProcessingMask = (function() {
	function T(tgt,msg) {

		var mask = '#tpl_processing_mask';
		var dialog = '#tpl_processing_dialog';
		var maskSet = $(mask).add($(dialog));

		// Set target
		if (typeof(tgt) == 'undefined') { tgt = '#tpl_page'; };
		tgt = $(tgt);
		tgt.css({ position: 'relative' }); // Required
		
		// Set message
		if (typeof(msg) == 'undefined') { msg = 'Please wait, processing...'; };		

		// Create mask, removing any existing
		maskSet.remove();

		// Create HTML for dialog
		var hMask = '\
<div id="tpl_processing_mask"></div>\
<div id="tpl_processing_dialog">\
	<div class="contents">\
		<p>'+msg+'</p>\
	</div>\
</div>';

		// Add elements
		tgt.append(hMask);

		// Grab elements
		mask = $(mask);
		dialog = $(dialog);
		
		// Set mask size and opacity [IE6]
		var h = tgt.height();
		var w = tgt.width();
		mask.css({
			opacity: 0.3,
			height: h + 'px',
			width: w + 'px'
		});
		
		// Position dialog
		var isIE6 = (($.browser.msie && ($.browser.version < 7)) ? true : false);
		if (isIE6) {
			dialog.center(true);
			dialog.css({
				top: '100px'
			});
		}
		else {
			dialog.center();
		};

		// Hide dropdowns
		$('select').css({visibility: 'hidden'});
		
		//Show mask
		maskSet.show();

	}
	
	return T;
})();


// Function to create and show processing mask
TWIG.hideProcessingMask = (function() {
	function T(delay) {

		var mask = $('#tpl_processing_mask');
		var dialog = $('#tpl_processing_dialog');
		var maskSet = mask.add(dialog);
		
		// Show dropdowns and hide mask
		function doHide() {
			$('select').css({visibility: 'visible'});
			maskSet.hide();		
		}
		
		if (typeof(delay) == 'number') {
			window.setTimeout(function() {
				doHide();
			}, delay);
		}
		else {
			doHide();
		};
	}
	
	return T;
})();	
		
/* Twig Class */
