window.onload = function(){
	// PRODUCT SELECTION
	if (document.getElementById('selectForm')) {
		boxen.init({
			formID:'selectForm', 
			totalItemsID:'totalItems', 
			totalCartonsID:'totalCartons', 
			totalPriceID:'totalPrice',
			highlightClass:'productLine',
			cartonID:'cartons',
			freightByWeight:false,
			cartonWeight:1000,
			cartonFlashParams:{
				url:'../_assets/ui/cartons.swf',
				width:220,
				height:140,
				version:6,
				bgColor:'#FFFFFF'
			}
		})
	}
	// SHIPPING
	else if (document.getElementById('orderDelivery')) {
		happyError.init('orderDelivery');
		happyShipping.init('freight', 'totalShipping', 'totalPrice');
	}
	// PAYMENT
	else if (document.getElementById('orderBilling')) {
		happyError.init('orderBilling');
		// happySwitch.init(['Customer_Payment_Type_Credit', 'Customer_Payment_Type_Cheque'], 'blockGroup');
		happyCopy.init('copyDetails', ['Stored_Billing_Name', 'Stored_Billing_Address', 'Stored_Billing_Town', 'Stored_Billing_Postcode', 'Stored_Billing_State', 'Stored_Billing_Country'], ['Billing_Name', 'Billing_Address', 'Billing_Town', 'Billing_Postcode', 'Billing_State', 'Billing_Country']);
	}
}

/*	----------------------------------------------------------------------
	BOXEN 
	Fancy little script to drive our wine carton update interface.
	All packed into an object in order to avoid polluting the namespace. YAY!
	
	The following classes may be used:
		* unitprice_12-30		- Unit price.
		* unitweight_12.34	- Unit Weight, in grams.
		* maximum_12			- Maximum user can buy
		* minimum_2				- Minimum user can buy
		* modifier_1			- For items sold in cases only
		* caseprice_12-30		- Discounted price when user buys a case worth
		* casesize_12			- How large is a case then?
	---------------------------------------------------------------------- */
boxen = {
	inputs: [],
	totalCartons: 0,
	totalItems: 0,
	totalPrice: 0,
	totalPriceNode: 0,
	totalItemsNode: 0,
	totalCartonsNode: 0,
	totalWeight: 0,
	highlightClass: null,
	freightByWeight: false,
	cartonWeight: 1000,
	boxenNode: null,
	bonusNode: null,
	bonusSwitch: null,
	// INITALISE
	// Collect inputs, assign handlers, store config details
	init: function(options) {
		form = document.getElementById(options.formID);
		// Check for bonuses
		if (options.bonusNode) {
			this.bonusNode = document.getElementById(options.bonusNode);
			formClasses = form.className.split(' ');
			for (var h = 0; h < formClasses.length; h++) {
				if (formClasses[h].lastIndexOf('bonusunits') != -1) {
					bonus = formClasses[h].split('_');
					this.bonusSwitch = parseInt(bonus[1]);
				}
			}
		}
		// Init the quantity inputs
		inputs = form.getElementsByTagName('input');
		for (var i = 0; i < inputs.length; i++) {
			if (inputs[i].className.lastIndexOf('quantity') != -1) {
				// set up local vars to store extracted values
				var maximum 	= null;
				var minimum 	= null;
				var unitPrice 	= null;
				var modifier 	= null;
				var casePrice 	= null;
				var caseSize 	= 12; //Set the default case size here:
				var unitWeight 	= null;
				// loop through all the classnames
				classes = inputs[i].className.split(' ');
				for (var j = 0; j < classes.length; j++) {
					// get the modifier
					if (classes[j].lastIndexOf('modifier') != -1) {
						modifier = classes[j].split('_');
						modifier = parseInt(modifier[1]);
					}
					// get the unit price
					else if (classes[j].lastIndexOf('unitprice') != -1) {
						unitPrice = classes[j].split('_');
						unitPrice = parseFloat(unitPrice[1].replace(/-/, '.')); // Swap out the hypen for a decimal
					}
					// get the case price
					else if (classes[j].lastIndexOf('caseprice') != -1) {
						casePrice = classes[j].split('_');
						casePrice = parseFloat(casePrice[1].replace(/-/, '.')); // Swap out the hypen for a decimal
					}
					// get the maximum
					else if (classes[j].lastIndexOf('maximum') != -1) {
						maximum = classes[j].split('_');
						maximum = parseInt(maximum[1]);
					}
					// get the minimum
					else if (classes[j].lastIndexOf('minimum') != -1) {
						minimum = classes[j].split('_');
						minimum = parseInt(minimum[1]);
					}
					// Case size
					else if (classes[j].lastIndexOf('casesize') != -1) {
						caseSize = classes[j].split('_');
						caseSize = parseInt(caseSize[1]);
					}
					// Case price
					else if (classes[j].lastIndexOf('unitweight') != -1) {
						unitWeight = classes[j].split('_');
						unitWeight = parseFloat(unitWeight[1]);
					}
					
				}
				// Check to see if the modifier is up to date, else set a default
				if (modifier == null) {
					modifier = 1;
				}
				// Store extracted values
				this.inputs[inputs[i].id] = {
						modifier:modifier, 
						node:inputs[i], 
						unitPrice:unitPrice,
						unitWeight:unitWeight,
						totalWeight:0, 
						maximum:maximum,
						minimum:minimum,
						caseSize:caseSize,
						casePrice:casePrice, 
						totalItems:0,
						totalPrice:0, 
						totalNode: document.getElementById(inputs[i].id + 'Total') // This is a bit brittle...
				};
				var boxObj = this;
				inputs[i].onblur = function(){boxObj.update(this)};
			}
		}
		// Collect the totals (add tests to see if they are there)
		this.totalPriceNode = document.getElementById(options.totalPriceID);		
		this.totalItemsNode = document.getElementById(options.totalItemsID);
		this.totalCartonsNode = document.getElementById(options.totalCartonsID);
		// Insert our flash cartons
		if (options.cartonID && options.cartonFlashParams) {			
			var fo = new FlashObject(
				options.cartonFlashParams.url,
				'boxen',
				options.cartonFlashParams.width,
				options.cartonFlashParams.height,
				options.cartonFlashParams.version,				
				options.cartonFlashParams.bgColor
				);
			fo.write(options.cartonID);
			this.boxenNode = document.getElementById('boxen');			
		}	
		// See the highlightClass. This is the class used to pick the parent we need to highlight
		if (options.highlightClass) {
			this.highlightClass = options.highlightClass;
		}
		// See how the cartons need to be updated
		if (options.freightByWeight) {
			this.freightByWeight = options.freightByWeight;
		}
		// Need to add code for the flash file later.
		// Update the display... this deals with inital values, and firefox caching values
		this.updateAll();
	},
	// UPDATE TOTALS
	// This is called when a single input has had it's value changed
	update: function(node) {
		this.updateInput(node);
		this.updateTotals();
	},
	// UPDATE TOTALS FOR ONE INPUT
	updateInput: function(node) {
		input = this.inputs[node.id];
		// Basic validation
		if (isNaN(input.node.value)) {
			happyError.showErrors(node, ['Whole numbers only']);
			var newValue = parseInt(node.value);
			if (isNaN(newValue)) {
				node.value = 0;
			}
			else {
				node.value = parseInt(node.value);
			}			
		}
		// Validate maximum
		if (input.node.value > input.maximum && input.maximum != null) {
			input.node.value = input.maximum;
			// Display an error stating the maximum
		}
		// Validate minimum
		if (input.node.value < input.minimum && input.minimum != null && input.node.value != 0) {
			input.node.value = input.minimum;
			// Display an error stating the minimum
		}
		// Check to for case modifiers
		if (input.caseSize != null) {
			if (input.node.value >= input.caseSize) {
				// Figure out how many cartons
				var remainder = input.node.value % input.caseSize;
				var cartons = (input.node.value - remainder) / input.caseSize;
				input.totalPrice = (cartons * input.casePrice) + (remainder * input.unitPrice);
			}
			else {
				input.totalPrice = input.unitPrice * input.node.value;
			}
		}
		else {
			input.totalPrice = input.unitPrice * input.node.value;
		}
		// Total weight. Case weight is accounted for using the modifier
		if (this.freightByWeight) {
			input.totalWeight = (input.node.value * input.modifier) * input.unitWeight;
		}
		// Then figure out the totals items
		input.totalItems = input.node.value * input.modifier;
		// Update the total node
		input.totalNode.innerHTML = currencyFormatter(input.totalPrice);
		// Check to see if we need to toggle the highlight too
		if (this.highlightClass != null) {
			if (node.value > 0) {
				this.toggleHighlight(node, true);
			}
			else {
				this.toggleHighlight(node, false);
			}
		}
	},
	toggleHighlight: function(node, state) {
		target = node;
		do {
			target = target.parentNode;
		} while(target.className.lastIndexOf(this.highlightClass) == -1)
		if (state == true) {
			addClass(target, 'highlight');
		}
		else {
			removeClass(target, 'highlight');
		}
	},
	// UPDATE TOTAL
	// This loops through all the stored inputs, builds the totals
	// and then updates the total display. Also calls the flash update
	updateTotals: function() {		
		this.totalItems 	= 0;
		this.totalPrice 	= 0;
		this.totalWeight 	= 0;
		// May need to change depending if we use a has or literal
		for (var i in this.inputs) {			
			// IE 5 add an additional property to the hash table. We need to exclude it
			if (this.inputs[i].totalItems) {
				this.totalItems 	+= this.inputs[i].totalItems;
				this.totalPrice 	+= this.inputs[i].totalPrice;
				this.totalWeight 	+= this.inputs[i].totalWeight;
			}
		}
		// Update displays
		this.totalItemsNode.innerHTML = this.totalItems;		
		this.totalPriceNode.innerHTML = currencyFormatter(this.totalPrice);
		// Do we need to display the bonus?
		if (this.bonusNode != null) {
			if (this.totalItems >= this.bonusSwitch) {
				this.bonusNode.style.visibility = 'visible';
			}
			else {
				this.bonusNode.style.visibility = 'hidden';
			}
		}
		this.updateCartonTotal();
	},
	// UPDATE CARTON TOTAL CARTONS
	// Work out total cartons based on the weight
	updateCartonTotal: function() {
		// Figure out total cartons
		if (this.freightByWeight == true) {
			remainder = this.totalWeight % this.cartonWeight
			this.totalCartons = this.totalWeight / this.cartonWeight;
			this.totalCartons = (this.totalWeight - remainder) / this.cartonWeight;
			if (remainder != 0) {
				this.totalCartons += 1;
			}
		}
		else {
			remainder = this.totalItems % 12;
			this.totalCartons = (this.totalItems - remainder) / 12;
			if (remainder != 0) {
				this.totalCartons += 1;
			}
		}
		this.totalCartonsNode.innerHTML = this.totalCartons;
		// Update the flash file
		if (this.boxenNode != null) {			
			this.updateCarton(this.totalItems);
		}
	},
	// UPDATE ALL THE INPUT TOTALS
	// Usually used when we first load up the page
	updateAll: function() {
		for (var i in this.inputs) {
			if (this.inputs[i].node) {
				this.updateInput(this.inputs[i].node);
			}
		}
		this.updateTotals();
	},
	// UPDATE CARTON
	// This updates the flash file. Pretty simple right now but
	// will get a bit more complicated when we change our flash file
	// For now it's not even checking if it's loaded
	updateCarton: function(items) {
		if (this.boxenNode.PercentLoaded() == 100) {
			this.boxenNode.GotoFrame(items);
		}
		else {
			box = this.boxenNode;
			window.setTimeout('box.GotoFrame(' + items + ')', 2000)
		}
	}
}

/*	----------------------------------------------------------------------
	VALIDATION 
	Some simple validations. These are packed into a literal object to
	prevent name collisions. The logic may improve in the future, but
	the interface will likely remain the same.
	
	May need something to deal with dependencies. IE, if we have a
	credit number, we need to know the card type to validate it.
	Same with checking the expiry on a card.
	
	Works with one form at a time.
	
	Handles the following validations
		* he-Required 		- Must not be empty
		* he-Integer		- Whole numbers only
		* he-Float			- Numbers only
		* he-Email			- Valid email address
		* he-Phone			- Valid australian phone number
		* he-CreditNumber	- Valid credit card
		* he-CreditType	- Credit card vendor
		* he-CreditYear	- Valid expiry for credit card
		* he-CreditMonth	- Valid expiry for credit card
		* he-Depend_ID 	- A dependent field
	---------------------------------------------------------------------- */
happyError = {
	formNode: null,
	errorNode: null,
	errorTimeout: null,
	inputs: [],
	required: [],
	hasRequiredFields: false,
	// INITALISE
	// Figures out what the items need to be validated against, and
	// stores em for later. Attaches the events.
	init: function(formID) {
		this.formNode = document.getElementById(formID);
		// Get the inputs
		var inputs = this.formNode.getElementsByTagName('input');
		this.extractValidations(inputs);
		// Get the textareas
		var textareas = this.formNode.getElementsByTagName('textarea');
		this.extractValidations(textareas);
		// Get the selects
		var selects = this.formNode.getElementsByTagName('select');
		this.extractValidations(selects);
		// If it has required fields, attach this 'ere event
		if (this.hasRequiredFields) {
			var errorObj = this;
			this.formNode.onsubmit = function(){errorObj.checkRequiredFields();return false;}
		}
	},
	// EXTRACT VALIDATIONS
	// This extracts the validations, and attaches events
	extractValidations: function(nodes) {
		for (var i = 0; i < nodes.length; i++) {
			if (nodes[i].className) {
				classes = nodes[i].className.split(' ');
				var validations = [];
				var dependencies = null;
				for (var j = 0; j < classes.length; j++) {
					// See if this class name has the validation prefix
					if (classes[j].lastIndexOf('he-') != -1) {
						validation = classes[j].split('-');
						validation = validation[1];
						// Check for required fields
						if (validation == 'required') {
							this.required.push(nodes[i]);
							this.hasRequiredFields = true;
						}
						// Check for dependency
						// Only supports single dependency for now
						else if (validation.lastIndexOf('depend') != -1) {
							dependencies = validation.split('_');
							dependencies = dependencies[1];
						}
						else {
							validations.push(validation);
						}
					}
					// Only store it if we actually have any validations
					if (validations.length > 0) {
						this.inputs[nodes[i].id] = {
							node:nodes[i],
							validations:validations,
							dependencies:dependencies
						}
						var errorObj = this;
						nodes[i].onchange = function(){errorObj.validate(this);}
					}
				}
			}
		}	
	},
	// VALIDATE AN INPUT
	// Node is required. Validations is option. Is an array of strings.
	// If it is provided, those validations are used instead of any cached.
	validate: function(node, optValidations) {
		// Check for optional validations (non-cached)
		var validations;
		if (optValidations) {
			validations = optValidations;
		}
		else {
			validations = this.inputs[node.id].validations;
		}
		// Add logic for checkboxes
		var value = node.value;
		var errors = [];
		// Validate
		for (var i = 0; i < validations.length; i++) {
			var check = this['valid_' + validations[i]](node);
			if (check != true) {
				errors.push(check);
			}
		}
		// Display errors if we have any
		// In the future have validations return an array.
		// true/false, message, node
		if (errors.length > 0) {
			this.showErrors(node, errors);
		}
	},
	// CHECK REQUIRED FIELDS
	checkRequiredFields: function() {
		var invalid = false;
		for (var i = 0; i < this.required.length; i++) {
			if (this.required[i].value == '' || this.required[i].value == ' ') {
				invalid = true;
				// highlight the field
				addClass(this.required[i], 'attention');
			}
		}
		if (invalid) {
			alert('There are required fields you need to fill out.\n These are highlighted.');
			return false;
		}
		else {
			this.formNode.submit();
		}
	},
	// ERROR CACHE
	addError: function() {
		
	},
	// SHOW ERRORS
	// Gets passed a node and an array of error messages. Displays em. Easy.
	// Optionally we may do some stuff to allow different displays.
	showErrors: function(node, messages) {
		// Collect the errors into a string
		var message = '';
		for (var i = 0; i < messages.length; i++) {
			message += messages[i] + '\n';
		}
		//alert(message);
		// Inialise the error display
		if (this.errorNode == null) {
			this.errorNode = document.createElement('div');
			this.errorNode.className = 'error';
		}
		else {
			// make sure it's not sitting in the document
			this.hideErrors();
		}
		this.errorNode.innerHTML = message;
		// Position it, stick it in the page
		node.parentNode.style.position = 'relative';
		this.errorNode.style.left = node.offsetLeft + node.offsetWidth + 'px';
		this.errorNode.style.top = node.offsetTop + 'px';
		node.parentNode.appendChild(this.errorNode);
		// Add events to hide the error 
		errorObj = this;
		node.onfocus = function() {errorObj.hideErrors();}
		// I HATE HAVING TO PASS A GOD_DAMN STRING!
		this.errorTimeout = window.setTimeout('happyError.hideErrors()', 4000);
	},
	hideErrors: function() {
		if (this.errorNode.parentNode) {
			parentNode = this.errorNode.parentNode;
			parentNode.removeChild(this.errorNode);
		}
		window.clearTimeout(this.errorTimeout);
	},
	// VALIDATIONS
	// Oh, lot's of 'em! Either return true, or a string, which is the error message
	valid_integer: function(node) {
		value = node.value
		// need to actually Check if this a WHOLE NUMBER!!! DERRR!
		if (isNaN(value) == true) {
			var error = 'Whole numbers only.';
			return error;
		}
		else {
			return true;
		}
	},
	valid_phone: function(node) {
		value = node.value;
		var filter  = /^(\(?\+?[0-9]*\)?)?[0-9_\- \(\)]*$/;
		if (!filter.test(value.toString())) {
			var error = 'Numbers only for your phone or fax number.';
			return error;
		} 
		else {
			return true;
		}
	},
	valid_email: function(node) {
		value = node.value;
		var x = value;
		var filter  = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
		if (!filter.test(x)) {
			var error = 'This is not a valid email address.';
			return error;
		}
		else {
			return true;
		}
	},
	valid_creditNumber: function(node) {
		value = node.value;
		dependentID = this.inputs[node.id].dependencies;
		cardType = document.getElementById(dependentID).value;
		return this.checkCreditNumber(value, cardType);
	},
	valid_creditType: function(node) {
		value = node.value;
		numberNode = document.getElementById(this.inputs[node.id].dependencies);
		cardNumber = numberNode.value;
		return this.checkCreditNumber(cardNumber, value);
		// can't reset the target node with this style
	},
	checkCreditNumber: function(value, cardType) {
		if (isNaN(value)) {
			error = 'Please use numbers only (no spaces)';
			return error;
		}
		// Check the card type and do the checks based on that
		var cardNumber = value.toString();
		var startTest;
		switch(cardType) {
			case 'Visa':
				// VISA
				startTest = parseInt(cardNumber.slice(0, 1));
				if (startTest != 4) {
					error = 'This is not a valid Visa number';
					return error;
				}
			break;
			case 'MasterCard':
				// MASTERCARD
				startTest = parseInt(cardNumber.slice(0, 1));
				if (startTest != 5) {
					error = 'This is not a valid Mastercard number';
					return error;
				}
			break;
			case 'American Express':
				// AMERICAN EXPRESS
				startTest = parseInt(cardNumber.slice(0, 2));
				if (startTest != 37) {
					error = 'This is not a valid American Express number';
					return error;					
				}
			break;
			case 'BankCard':
				// BANKCARD
				startTest = parseInt(cardNumber.slice(0, 4));
				if (startTest != 5610) {
					error = 'This is not a valid BankCard number';
					return error;					
				}
			break;
			case 'Diners':
				// DINERS CLUB
				startTest = parseInt(cardNumber.slice(0, 1));
				if (startTest != 3) {
					error = 'This is not a valid Diners Club number';
					return error;					
				}
			break;
		}
		return true;
	},
	valid_creditYear: function(node) {
		value = node.value;
		if (isNaN(value) || value == 0) {
			error = 'This is not a valid year'
			return error;
		}		
		else {
			today = new Date();
			// turn the test value into an oughtie number
			var testValue = value.toString();
			testValue = parseInt(20 + testValue);
			// Now lets check it out
			if (testValue <= today.getFullYear() - 1) {
				error = 'This expiry date is invalid';
				return error;
			}
			else {
				return true;
			}
		}
	},
	valid_creditMonth: function(node) {
		value = node.value;
		if (value > 12 || isNaN(value) || value == 0) {
			error = 'Please use a value between 1 and 12'
			return error;
		}
		else {
			return true;
		}
	},
	// UTILITY METHODS FOR VALIDATION
	getDependentNode: function(nodeID) {
		return document.getElementById(this.inputs[nodeID].dependencies);
	}
}

/*	----------------------------------------------------------------------
	SHIPPING
	Doesn't do too much. It just updates the totals when the user changes
	the shipping.
	---------------------------------------------------------------------- */
happyShipping = {
	inputs: [],
	shippingNode: null,
	totalPriceNode: null,
	totalPrice: 0,
	init: function(optionBoxID, shippingID, totalID) {
		// Collect inputs and prices
		var box = document.getElementById(optionBoxID);
		var inputs = box.getElementsByTagName('input');
		for (var i = 0; i < inputs.length; i++) {
			if (inputs[i].className.lastIndexOf('shippingDestination') != -1) {
				price = inputs[i].className.slice((inputs[i].className.lastIndexOf('price_')+6), inputs[i].className.length)
				price = parseFloat(price); // Dirty hack coz it returns a match and sub-match
				this.inputs[inputs[i].id] = {node:inputs[i], price:price};
				// Attach events
				shippingObj = this;
				inputs[i].onclick = function() {shippingObj.update(this);}
			}
		}
		// Get the total nodes and their prices
		this.shippingNode = document.getElementById(shippingID);
		this.totalPriceNode = document.getElementById(totalID);
		this.totalPrice = this.extractPrice(this.totalPriceNode.innerHTML);
	},
	extractPrice: function(oldPrice) {
		newPrice = parseFloat(oldPrice.slice(1, oldPrice.length));
		return newPrice;
	},
	update: function(node) {
		shipping = this.inputs[node.id].price;
		newPrice = currencyFormatter(this.totalPrice + shipping);
		this.shippingNode.innerHTML = currencyFormatter(shipping);
		this.totalPriceNode.innerHTML = newPrice;
	}
}
/*	----------------------------------------------------------------------
	HAPPY COPY
	Takes values from a set of fields, and copies them to a second set
	Good for populating text inputs from hidden fields:
	---------------------------------------------------------------------- */
happyCopy = {
	sourceFields: null,
	targetFields: null,
	triggerElement: null,
	copied: false,
	init: function(trigger, arrSourceFields, arrTargetFields) {
		if (document.getElementById(trigger)) {
			//Assign events to the trigger object:
			this.triggerElement = document.getElementById(trigger);
			this.triggerElement.onchange = function() {happyCopy.copyFields()};
			this.triggerElement.onclick = function() {happyCopy.copyFields()};
				if (this.triggerElement.checked == true) {
					this.triggerElement.checked = false;
				}
				this.sourceFields = arrSourceFields;
				this.targetFields = arrTargetFields;
		}
	},
	copyFields: function() {
		if (!this.copied) {
			//the trigger, source and target fields must be siblings within the same fieldset:
			for (var n=0;n<this.sourceFields.length;n++) {
				if (document.getElementById(this.targetFields[n])) {
					if (document.getElementById(this.targetFields[n]).type == 'select') {
						for (var k = 0; k < selects[h].childNodes.length; ++k) {
							if (selects[h].childNodes[k].value == inputs[i].value) {
								selects[h].childNodes[k].selected = 'selected';
							} else {
								selects[h].childNodes[k].selected = false;
							}
						} 
					} else {
						document.getElementById(this.targetFields[n]).value = document.getElementById(this.sourceFields[n]).value;
					}
				}
			}
			this.copied = true;
		}
	}
}
/*	----------------------------------------------------------------------
	HAPPY SWITCH
	This lets us toggle between a set of options. Only handles one for now
	but in the future this will expand to handle more.
	---------------------------------------------------------------------- */
happySwitch = {
	switches: [],
	init: function(switches, blockClass) {
		for(var i = 0; i < switches.length; i++) {
			node = document.getElementById(switches[i]); 
			block = node; 
			do {
				block = block.parentNode;
			} while(block.className.lastIndexOf(blockClass) == -1);
			var children = [];
			children = this.collectNodes(children, block, 'input');
			children = this.collectNodes(children, block, 'select');
			this.switches[switches[i]] = {children:children, id:switches[i], node:node};
			// attach event
			switchObj = this;
			node.onchange = function(){switchObj.flick(this);}
		}
		for (var j in this.switches) {
			if (this.switches[j].node.checked == true) {
				this.flick(this.switches[j].node);
			}
		}
	},
	collectNodes: function(collection, boss, nodeName) {
		newCollection = boss.getElementsByTagName(nodeName);
		for (var i = 0; i < newCollection.length; i++) {
			collection.push(newCollection[i]);
		}
		return collection;
	},
	flick: function(node) {
		for (var i in this.switches) {
			children = this.switches[node.id].children;
			// disable em
			if (this.switches[i].id != node.id) {
				for (var j = 0; j < children.length; j++) {
					if (children[j].id != this.switches[i]) {
						children[j].disabled = 'disabled';
						addClass(children[j], 'disabled');						
					}					
				}
			}
			// enable em
			else {
				for (var j = 0; j < children.length; j++) {
					children[j].enabled = true;
					removeClass(children[j], 'disabled');
				}
			}
		}
	}
}

/*	----------------------------------------------------------------------
	UTILITY FUNCTIONS
	Functions for some more common stuff. Mainly formatting, but also
	some short cuts to DOM methods.
	---------------------------------------------------------------------- */
// CURRENCY FORMATTER
function currencyFormatter(amount) {
	var i = parseFloat(amount);
	if(isNaN(i)) { i = 0.00; }
	var minus = '';
	if(i < 0) { minus = '-'; }
	i = Math.abs(i);
	i = parseInt((i + .005) * 100);
	i = i / 100;
	s = new String(i);
	if(s.indexOf('.') < 0) { s += '.00'; }
	if(s.indexOf('.') == (s.length - 2)) { s += '0'; }
	s = minus + s;
	return '$' + s;
}
// CREATE DOM NODE SHORTCUT
// ADD/REMOVE CLASSNAME
function addClass(element, className) {
	var classes = element.className.split('');
	// Check to see if it exists, If it does skip out
	for (var i = 0; i < classes.length; i++) {
		if (classes[i] == className) {
			return;
		}
	}
	// Otherwise add it
	element.className = element.className + ' ' + className;
}
function removeClass(element, className) {
	var newClass = ''
	var classes = element.className.split(' ');
	for (var i = 0; i < classes.length; i++) {
		if (classes[i] != className) {
			newClass += classes[i] + ' ';
		}
	}
	// set the class
	element.className = rightTrim(newClass);
}
// TRIM STRING
function leftTrim(sString) {
	while (sString.substring(0,1) == ' ') {
		sString = sString.substring(1, sString.length);
	}
	return sString;
}
function rightTrim(sString) {
	while (sString.substring(sString.length-1, sString.length) == ' ') {
		sString = sString.substring(0,sString.length-1);
	}
	return sString;
}
