/**
 * Namespace declaration.
 */
var Products = {};


/**
 * @class
 * @base Class
 * 
 * Handles the expand/collapse sections of the RAME page.
 */
Products.Panel = new Class({
	
	initialize: function(header,content) {
		this.header = $(header);
		this.content = $(content);
		
		this.content.setStyle('overflow', 'hidden');
		this.header.addListener('click',this.onHeaderClick.bind(this));
		this.header.addListener('focus',this.onHeaderFocus.bind(this));
		this.header.addListener('blur',this.onHeaderBlur.bind(this));
		if(header.hasClass('closed')){
			this.close();
		}
	},
	
	open: function(){
		
		if(this.effect) {
			arguments.callee.delay(200, this);
			return;
		}
		
		this.effect = new Fx.Styles(this.content);
		this.effect.start({
			height: [0,this.content.scrollHeight],
			opacity: [0,1]
		}).chain(
			function(){
				this.header.removeClass('closed');
				this.header.addClass('open');
				delete this.effect;
			}.bind(this)
		)
			
	},
	
	close: function(){
		
		if(this.effect) {
			arguments.callee.delay(200, this);
			return;
		}
		
		this.effect = new Fx.Styles(this.content);
		this.effect.start({
			height: [this.content.scrollHeight,0],
			opacity: [1,0]
		}).chain(
			function(){
				this.header.removeClass('open');
				this.header.addClass('closed');
				delete this.effect;
			}.bind(this)
		)
		
	},
	
	isOpen: function(){
		return this.header.hasClass('open');
	},
	
	onHeaderClick: function(){
		if(this.isOpen()){
			this.close();
		} else {
			this.open();
		}
	},
	
	onHeaderFocus: function(){
		this.header.style.textDecoration='underline';
	},
	
	onHeaderBlur: function(){
		this.header.style.textDecoration='none';
	}
});

/**
 * @class
 * @base Class
 * 
 * Provides the top-level base for the Contact and RAME pages.
 */
Products.Form = new Class({
	
	/**
	 * Initialize the form and it's fields.
	 *
	 */
	initialize: function(element) {
		// Set up form
		this.element = element;
		if(this.element) {
			this.action = this.element.action;
			this.method = (this.element.method) ? this.element.method : "get";
			this.enctype = this.element.enctype;
			this.element.addEvent("submit", this.onSubmit.bindAsEventListener(this));
		}
		
		this.slaves = [];
		
		// Initialize 'fields' (drop downs)
		var fields = $$(".field");
		for (var i = 0; fields && i < fields.length; i++) {
			var field;
			switch(fields[i].id){
				case 'feedback':
					field = new Products.Form.FeedbackDropDownField(fields[i]);
					break;
				case 'product':
					field = new Products.Form.ProductDropDownField(fields[i]);
					break;
				case 'problem':
					field = new Products.Form.ProblemDropDownField(fields[i]);
					break;
				default:
					field = new Products.Form.DropDownField(fields[i]);
			}
			this.slaves.push(field);
			field.master = this;
		}
		
		// Initialize text fields
		var texts = $$(".text");
		for(var i = 0; texts && i < texts.length; i++) {
			var field;
			switch(texts[i].id){
				case "email":
					field = new Products.Form.EmailField(texts[i]);
					break;
				case "contact_email":
					field = new Products.Form.EmailField(texts[i]);
					break;
				case "contactNumber":
					field = new Products.Form.ContactNumberField(texts[i]);
					break;
				default:
					if (texts[i].tagName == 'TEXTAREA') {
						field = new Products.Form.TextArea(texts[i]);
					} else {
						field = new Products.Form.Field(texts[i]);
					}
			}
			
			this.slaves.push(field);
			field.master = this;
		}
		
		// Initialize checkboxes
		var checkboxes = $$(".checkbox");
		for(var i = 0; checkboxes && i < checkboxes.length; i++) {
			var checkbox;
			switch (checkboxes[i].id) {
				case "contact_email":
					checkbox = new Products.Form.Checkbox.EmailContactPreferred(checkboxes[i]);
					break;
				case "contact_phone":
					checkbox = new Products.Form.Checkbox.PhoneContactPreferred(checkboxes[i]);
					break;
				case "emailCopy":
					checkbox = new Products.Form.Checkbox.EmailCopy(checkboxes[i]);
					break
				case "emailSubscribe":
					checkbox = new Products.Form.Checkbox.EmailSubscribe(checkboxes[i]);
					break
				default:
					checkbox = new Products.Form.Checkbox(checkboxes[i]);
					break;
			}
			
			this.slaves.push(checkbox);
			checkbox.master = this;
		}
		
		// Initialize sections
		var sections = $$(".fieldsetTop");
		
		for(var i = 0; sections && i < sections.length; i++) {
			var element = sections[i].getNext();
			var control  = sections[i].getFirst();
			if(control.getTag() != "a") {
				continue;
			}
			new Products.Panel(control,element);
		}
		
		// Initialize the upload buttons
		var uploads = $$(".upload_button");
		for(var i = 0; uploads && i < uploads.length; i++) {
			var upload = new Products.Form.Upload(uploads[i]);
			upload.master = this;
			this.slaves.push(upload);
		}
		
		var productCounter;
		//initially set the products field to be not required
		for (var j = 0; j < this.slaves.length; j++) {
			if (this.slaves[j].id == "product") {
				productCounter = j;
				this.slaves[productCounter].setRequired(false);
				break;
			}
		}
		//If a user fills out the form, goes to another page and then clicks browser back, check if
		//the products and camefrom fields need to be displayed
		for (var i = 0; i < this.slaves.length; i++) {
			//if the contacts form is a product enquiry, show the field and make it required 			
			if (this.slaves[i].id == "feedback" && this.slaves[i].getValue() == "Product Enquiry") {				
				this.slaves[productCounter].setRequired(true);
				$('productcontainer').style.display = 'block';
			}
			//if the Report a map error form's problem is any of the last 5 options, show the camefrom field
			if (this.slaves[i].id == "problem" && (this.slaves[i].getValue().substring(9,22) == "map on Yellow"
			||this.slaves[i].getValue().substring(9,26) == "map on WhitePages"
			||this.slaves[i].getValue().substring(9,26) == "map on CitySearch"
			||this.slaves[i].getValue().substring(9,28) == "map on another site"
			||this.slaves[i].getValue().substring(9,12) == "API")) {
				$('hidecamefrom').style.display = 'block';
			}
			if (this.slaves[i].id == ("searchDescription") ||
				this.slaves[i].id == ("directionDescription") ||
				this.slaves[i].id == ("mapDescription")) {
				
				if (this.slaves[i + 1].id == this.slaves[i].id + "Dummy") {			
					this.slaves[i].element.value = this.slaves[i+1].element.getValue();
				}
			}
		}
	},
	
	/**
	 * Ensure the required fields have been filled out.
	 */
	verify: function() {
		var verified = true;
					
		for(var i = 0; i < this.slaves.length; i++) {
			
			//if the slave has no validation forget about it
			if(!this.slaves[i].verify) {
				continue;
			}
			
			// if all is well clear the error message, else flag the failure
			if(this.slaves[i].verify()){
				this.slaves[i].clearError();
			} else {
				verified = false;
			}
		}
		return verified;
	},
	busy: function() {
		//if not already busy
		if(!this.modal){
			this.modal = new Element("div", {"class": "modal"});
		
			var dialog = new Element("div", {"class": "modal_dialog"});
		
			dialog.setHTML("<p>Sending...</p>");
		
			this.modal.appendChild(dialog);
		
			document.body.appendChild(this.modal);
		}
	},
	
	idle: function() {
		//if busy
		if(this.modal) {
			this.modal.remove();
			this.modal = null;
		}
	},
	
	onSubmit: function(event) {
		event = new Event(event);
		event.stop();
		
		if(!this.verify()) {
			// Not filled out correctly yet
			return;
		}
		this.busy();
		this.execute();		
		if($("emailSubscribea").hasClass("checked")){
			var subscription = new Products.Subscription;
			subscription.handleSubmit();
		}
		//alert("Submitted");
	},
	
	onBlur: function() {
	
	},
	
	onFocus: function() {
	
	},
	
	onComplete: function(response) {
		// Check the response
	},
	
	onSuccess: function() {
		this.idle();
	},
	
	onFailure: function(response) {
	
	},
	
	onActive: function(control, element) {
		control.addClass("open");
		control.removeClass("closed");
	},
	
	onBackground: function(control, element) {
		control.removeClass("open");
		control.addClass("closed");
	},

	/**
	* Select a field from the form. Wraps around the slaves array and is used to allow fields to influence each other.
	* It is worth noting that this function cannot be used in initialize functions as part of startup as it is not 
	* available/usable until Products.Form has initialized.
	* 
 	* @param {String} fieldId
 	*/
	getFieldById: function(fieldId){
		for(var i=0;i<this.slaves.length;i++){
			if(this.slaves[i].id == fieldId){
				return this.slaves[i];
			}
		}
		return null;
	}
});

/**
 * @class
 * @base Products.Form
 * 
 * Provides Contact Form specific code such as JSON-based submit code.
 */
Products.Form.Contact = Products.Form.extend({
	type: 'contact',
	
	initialize: function(element) {
		this.parent(element);
		
	},
	execute: function(){

		if(!this.verify()) {
			return;
		}
		
		this.busy();
	
		// Pick up a load of data from the form
		var payload = function(){
			var t = {};
			this.slaves.each(function(slave){
				if (slave.id == "message") {
					t[slave.getName()] = encodeURIComponent(slave.master.encodeHTML(slave.getValue()));
				}
				else {
					t[slave.getName()] = encodeURIComponent(slave.getValue());
				}
			})
			return t;
		
		}.bind(this)();
		
		var errorFn = function(result){
			this.idle();
			this.showError();
		}.bind(this);
		
		var successFn = function(result){
			if (result.error) {
				errorFn();
				return;
			} 
			
			this.idle();
			this.showSuccess();
		}.bind(this);
		
		new Json.Remote("../submitcontact", {
			onSuccess: successFn,
			onFailure: errorFn,
			onException: errorFn
		}).send(payload);
		
		$('errormessage').style.display='none';
	},
	/**
	 * encodes a given string into its HTML encoded version. E.G. <html> becomes &lthtml&gt  .
	 * this is used to prevent cross site scripting and is done by creating a temporary div 
	 * and returning the inner html of the text withing the div. In this way the browser does the encoding for us.
	 * @param {String} formText
	 */
	encodeHTML : function(formText){
		 var div = document.createElement('div');
  		 var text = document.createTextNode(formText);
  		 div.appendChild(text);
   		 return div.innerHTML;
	},
	showError: function(){
		$('errormessage').style.display='block';
	},
	showSuccess: function(){
		$("postsubmit").style.display='block';
		$("presubmit").style.display='none';
	}
});

/**
 * @class
 * @base Products.Form
 * 
 * Provides RAME specific code, uses a mime/multipart sumbit as it has upload fields which cannot JSON'ed
 */
Products.Form.Report = Products.Form.extend({
	type: 'report',
	
	initialize: function(element) {
		this.parent(element);
		
		if(window.location.hash == '#success'){
			$('successmessage').style.display='block';
		}
		if(window.location.hash == '#fail'){
			$('errormessage').style.display='block';
		}
		
	},
	/**
	 * encodes a given string into its HTML encoded version. E.G. <html> becomes &lthtml&gt  .
	 * this is used to prevent cross site scripting and is done by creating a temporary div 
	 * and returning the inner html. In this way the browser does the encoding for us.
	 * @param {String} formText
	 */
	encodeHTML : function(formText){
		 var div = document.createElement('div');
  		 var text = document.createTextNode(formText);
  		 div.appendChild(text);
   		 return div.innerHTML;
	},
	/**
	* This function is used to display a dummy description box over the real description box, so
	* the user does not see their description change to encoded HTML. Description field is the report
	* a map error description field type, and original value is the non-encoded user description of the 
	* problem they are reporting on.
 	* @param {String} descriptionField, {String}  originalValue
 	*/
	displayOriginalDescription: function(descriptionField, originalValue ){
			
			Form.getFieldById(descriptionField+'Dummy').element.value = originalValue;
			//hide the real description and show the dummy one
			Form.getFieldById(descriptionField).element.value = "";
			Form.getFieldById(descriptionField).element.setStyle('display', 'none');
			Form.getFieldById(descriptionField+'Dummy').element.setStyle('display','block');
	},
	
	onSubmit: function(event) {
		event = new Event(event);
		
		
		if(!this.verify()) {
			event.stop();
			return;
		}
		
		this.busy();
		
		for(var i=0;i<this.slaves.length;i++){
			if(this.slaves[i].element.value == this.slaves[i].defaultValue){
				this.slaves[i].element.value="";
				/*The description boxes need their contents HTML encoded to avoid
				 * the security issue of cross site scripting
				*/
			}else if(this.slaves[i].id ==("searchDescription")||
					 this.slaves[i].id ==("directionDescription")||
					 this.slaves[i].id ==("mapDescription")){
					 	
				var descriptionField = this.slaves[i].id;	
				var originalValue = this.slaves[i].element.getValue()	
				//display a dummy box over the description box with the unencoded HTML
				this.displayOriginalDescription(descriptionField, originalValue);
				//encode the HTML for the description box
				this.slaves[i].element.value = this.encodeHTML(originalValue);
			}
		}	
		
		return true;
	}
});

/**
 * @class
 * @base Class
 * 
 * Provides non-drop down input field functionality, often subclassed for specific verification code
 */
Products.Form.Field = new Class({
	initialize: function(element) {
		this.id = element.id;
		this.element = element;
		this.defaultValue = this.element.defaultValue;
		
		this.element.addEvent("focus", this.onFocus.bind(this));
		this.element.addEvent("blur", this.onBlur.bind(this));
		this.element.addClass("help_text");
		this.wrapper = this.element.getParent();
		this.errortext = $E(".errortext",this.wrapper);
		this.required = this.element.hasClass("required");
		if (this.errortext) {
			this.defaultError = this.errortext.innerHTML;
		}
		
		this.element.removeClass("help_text");
		if(!this.getValue() && this.getDefaultValue()) {
			this.element.value = this.getDefaultValue();
			this.element.addClass("help_text")
		}
	},
	
	getName: function() {
		return this.element.name;
	},
	
	getValue: function() {
		if(this.element.value && this.element.value.trim() != "" && this.element.value != this.getDefaultValue()) {
			return this.element.value.trim();
		}
		return "";
	},
	
	getDefaultValue: function() {
		return this.defaultValue;
	},

	hasFocus: function() {
		return this.element.hasClass("focus");
	},
	
	verify: function() {
		if (this.required) {
			if (this.getValue() == "" || this.getValue() == this.getDefaultValue() || this.getValue() == "---") {
				// Required field with empty value
				this.setError();
				return false;
			}
		}
		
		return true;
	},
	
	onFocus: function() {
		this.clearError();
		this.element.addClass("focus");
		this.element.removeClass("help_text");
		if(this.element.value == this.getDefaultValue()) {
			this.element.value = "";
		}
		if(this.container) {
			this.open();
		}
		
	},
	
	onBlur: function() {
		this.element.removeClass("focus");
		
		if(!this.getValue() && this.getDefaultValue()) {
			this.element.value = this.getDefaultValue();
			this.element.addClass("help_text")
		}
		
		if(this.container) {
			this.close();
		}
	},
	
	setError : function(errorMessage){
		this.wrapper.addClass("error");
		if (this.errortext && errorMessage) {
			this.errortext.setText(errorMessage || this.defaultError);
		}
	},
	clearError : function(){
		this.wrapper.removeClass("error");
	},
	setRequired : function(boolReq){
		this.required = boolReq;
		if(boolReq) {
			this.element.addClass("required");
		} else {
			this.element.removeClass("required");
		}
	}
});

/**
 * @class
 * @base Products.Form.Field
 * 
 * Provides TextArea specific validation
 */
Products.Form.TextArea = Products.Form.Field.extend({
	verify: function(){
		
		if(Form.type == 'contact'){
			return Products.Form.Field.prototype.verify.apply(this);
		} else if(Form.type == 'report'){
			//require at least one...
			if(
				Form.getFieldById('searchDescription').getValue() ==""
				&& Form.getFieldById('mapDescription').getValue() ==""
				&& Form.getFieldById('directionDescription').getValue() ==""
			){
				this.setError('Please enter at least one description');
				return false;
			} else if(this.element.getAttribute("maxlength") < this.getValue().length) {
				this.setError("This field must be less than "+this.maxlength+" characters long");
				return false;
			}
		} 
		
		return true;
	},
	
	clearError : function(){
		
		if (Form.type == 'contact') {
			this.wrapper.removeClass("error");
		} else if (Form.type == 'report') {
			//need to clear error on all
			Form.getFieldById('searchDescription').wrapper.removeClass("error");
			Form.getFieldById('mapDescription').wrapper.removeClass("error");
			Form.getFieldById('directionDescription').wrapper.removeClass("error");
		}
	}
});

/**
 * @class
 * @base Products.Form.Field
 * 
 * Provides Email specific validation
 */
Products.Form.EmailField = Products.Form.Field.extend({
	
	verify: function(){

		var hasValue = (this.getValue() != "");

		if (this.required && !hasValue) {
			this.setError('Please enter your email address');
			return false;
		} else if (hasValue){
			//Check it is valid
			if(! /^[A-Za-z0-9][A-Za-z0-9-_.]*[A-Za-z0-9-_]@[A-Za-z0-9-_]*\.[A-Za-z0-9-_.]*[A-Za-z]{2}$/.test(this.getValue())){
				this.setError('Invalid email Address');
				return false;
			}
		}
		
		return true;
	}
	
});

/**
 * @class
 * @base Products.Form.Field
 * 
 * Provides ContactNumber specific validation
 */
Products.Form.ContactNumberField = Products.Form.Field.extend({
	verify: function(){

		var hasValue = (this.getValue() != "");
		
		if (this.required && !hasValue) {
			this.setError('Please enter your phone number');
			return false;
		} else if (hasValue){
			//Check it is valid
			var valid = (/^[A-Za-z0-9 ]*$/.test(this.getValue()))
			if( !valid ){
				this.setError('Invalid phone number');
				return false;
			}
		}
		
		return true;
	}
});

/**
 * @class
 * @base Products.Form.Field
 * 
 * Provides generic DropDown feild functionality including blocking backspace from going back a page 
 * and closing drop-down if a user clicks elsewhere
 */
Products.Form.DropDownField = Products.Form.Field.extend({
	isOpen: false,
	initialize: function(element){
		Products.Form.Field.prototype.initialize.apply(this,arguments);
		
		var parent = this.element.getParent();
		this.topNode = parent;
		var child = $E(".field_control",parent);
		
		if(!child) {return;}
		
		this.control = child;
		this.control.addEvent("mousedown", this.onMousedown.bind(this));
		
		this.element.setStyle("cursor", "pointer");
		this.element.setAttribute("readOnly", "true");
		
		this.options = [];
			
		if(this.control.getPrevious().hasClass("field_options")) {
			var options = this.control.getPrevious().getChildren();
			for(var i = 0; options && i < options.length; i++) {
				this.options.push(options[i].innerHTML);
			}
		}
			
		// The container that holds the field options
		if(!Products.Form.Field.container) {
			Products.Form.Field.container = new Element("div", {"id": "field_container"});
			document.body.appendChild(Products.Form.Field.container);
		}
			
		this.container = Products.Form.Field.container;
		
		// This handles closing of drop down if someone clicks elsewhere
		document.addEvent(
			"click", 
			(function(event){
				event = new Event(event);
				var local = false;
				//walk up the tree to see if click was local
				for(var i = event.target; i!= window.document;i=i.parentNode){
					if(i==this.topNode){
						local=true;
					}
				}
				if(!local){
					if(this.isOpen){
						this.onBlur();
					}
				}
			}).bind(this)
		);
		
		// This prevents backspace working like the back button when in these fields
		document.addEvent(
			"keydown", 
			(function(event){
				event = new Event(event);
				var local = false;
				//walk up the tree to see if click was local
				for(var i = event.target; i!= window.document;i=i.parentNode){
					if(i==this.topNode){
						local=true;
					}
				}
				if(local && event.key=='backspace'){
					event.stop();
					event.preventDefault();
				}
			}).bind(this)
		);
	},
	
	open: function() {
		if(!this.container) {
			return;
		}
		
		// Blur the current field
		if(this.container.field) {
			this.container.field.onBlur();
		}
		
		this.container.field = this;
		this.element.addClass("focus");
		this.element.removeClass("error");
		if(this.element.value == this.getDefaultValue()) {
			this.element.value = "";
		}
		
		if(!this.options) {
			return;
		}
		
		// Empty the current content
		this.container.empty();
		
		// Fill out the options
		for(var i = 0; i < this.options.length; i++) {
			var anchor = new Element("a");
			anchor.setHTML(this.options[i]);
			anchor.field = this;
			anchor.addEvent("mouseenter", function() {
				this.addClass("hover");
			});
			anchor.addEvent("mouseleave", function() {
				this.removeClass("hover");
			});
			
			anchor.addEvent("mousedown", function() {
				this.field.element.value = this.innerHTML;
				this.field.onBlur();
			});
			
			this.container.appendChild(anchor);
		}
		
		// Set the position and width
		var width = this.element.getCoordinates().width + this.control.getCoordinates().width - 5;
		if(this.element.hasClass("required")) {
			width += 1;
		}
		this.container.setStyle("width", width);
		this.container.setStyle("left", this.element.getLeft());
		this.container.setStyle("top", this.element.getTop() + 21);
		
		this.container.addClass("open");
		this.isOpen = true;
	},
	
	close: function() {
		if(!this.container) {
			return;
		}
		
		this.container.removeClass("open");
		this.container.field = null;
		this.isOpen = false;
	},
	
	onMousedown: function() {
		if(!this.hasFocus()) {
			this.onFocus();
		}
		else {
			this.onBlur();
		}
	}
});

Products.Form.ProductDropDownField = Products.Form.DropDownField.extend({
	verify: function() {
		
		//Ignore this feild in validation if it is hidden
		if(this.required){
			return Products.Form.Field.prototype.verify.apply(this,arguments);
		} else {
			return true;
		}
	}
});

Products.Form.FeedbackDropDownField = Products.Form.DropDownField.extend({
	onBlur: function(){
		Products.Form.DropDownField.prototype.onBlur.apply(this,arguments);
		if(this.getValue() == 'Product Enquiry'){
			//show product field
			Form.getFieldById("product").setRequired(true);
			$('productcontainer').style.display = 'block';
		} else {
			//hide product field
			Form.getFieldById("product").setRequired(false);
			$('productcontainer').style.display = 'none';
		}
		
	}
});

Products.Form.ProblemDropDownField = Products.Form.DropDownField.extend({
	onBlur: function(){
		Products.Form.DropDownField.prototype.onBlur.apply(this,arguments);
		var val = this.getValue();
		if( // Use regex's as trying to match the Registered Trademark symbol is a dog.
			(/Whereis. map/.test(val)) || (/^Whereis. API$/.test(val))
		){
			//show product field
			$('hidecamefrom').style.display = 'block';
		} else {
			//hide product field
			$('hidecamefrom').style.display = 'none';
		}
		
	}
});
/**
 * @class
 * @base Class
 * 
 * Provides styled checkboxes, these boxes need to be readbale both as javascript objects and as form fields as Contact and Report forms
 * use different methods to sumbit.
 */
Products.Form.Checkbox = new Class({
	initialize: function(element) {
		this.id = element.id;
		this.formElement = element;
		this.element = new Element("a", {"class": "checkbox","href":"#"});
		this.element.addEvent("mousedown", this.onMousedown.bindAsEventListener(this));
		this.element.addEvent("click", this.onClick.bindAsEventListener(this));
		this.element.addEvent("keydown", this.onKeydown.bindAsEventListener(this));
		
		// Visually Swap out the real checkbox for our look-a-like, keep the orig so form submit has data
		this.name = this.formElement.name + 'a';
		this.element.injectBefore(this.formElement);
		this.formElement.setStyle('display','none');
		
		this.element.id = this.formElement.id + 'a';
		if(this.formElement.defaultChecked){
			this.element.addClass('checked');
		}
	},
	
	getName: function() {return this.name;},
	
	getValue: function() {return this.isChecked();},
	
	isChecked: function() {return this.element.hasClass("checked");},
	
	check: function() {
		this.formElement.checked=true;
		this.element.addClass("checked");
	},
	
	uncheck: function() {
		this.formElement.checked=false;
		this.element.removeClass("checked");
	},
	
	onClick: function(event) {
		event = new Event(event);
		event.stop();
	},
	onMousedown: function(event) {
		event = new Event(event);
		event.stop();
		this.toggle();
	},
	onKeydown: function(event) {
		event = new Event(event);
		if(["space","enter"].contains(event.key)){
			event.stop();
			this.toggle();
		}
		
	},
	
	toggle: function(){
		if(this.isChecked()){
			this.uncheck();
		} else {
			this.check();
		}
	}
});
Products.Form.Checkbox.EmailContactPreferred = Products.Form.Checkbox.extend({
	check: function() {
		Products.Form.Checkbox.prototype.check.apply(this);
		Form.getFieldById("email").setRequired(true);

	},
	uncheck: function() {
		Products.Form.Checkbox.prototype.uncheck.apply(this);
		if (!Form.getFieldById("emailCopy").isChecked()) {
			Form.getFieldById("email").setRequired(false);
		}
	}
});
Products.Form.Checkbox.PhoneContactPreferred = Products.Form.Checkbox.extend({
	check: function() {
		Products.Form.Checkbox.prototype.check.apply(this);
		Form.getFieldById("contactNumber").setRequired(true);

	},
	uncheck: function() {
		Products.Form.Checkbox.prototype.uncheck.apply(this);
		Form.getFieldById("contactNumber").setRequired(false);
	}
});
Products.Form.Checkbox.EmailCopy = Products.Form.Checkbox.extend({
	check: function() {
		Products.Form.Checkbox.prototype.check.apply(this);
		if (Form.getFieldById("email").required == false) {
			Form.getFieldById("email").setRequired(true);
		}
	},
	uncheck: function() {
		Products.Form.Checkbox.prototype.uncheck.apply(this);
		if (!Form.getFieldById("contact_email")){
			if (!Form.getFieldById("emailSubscribe").isChecked()) {
				Form.getFieldById("email").setRequired(false);
			}
		} else if (!Form.getFieldById("contact_email").isChecked()) {
			Form.getFieldById("email").setRequired(false);
		}
	}
});
Products.Form.Checkbox.PhoneContactPreferred = Products.Form.Checkbox.extend({
	check: function() {
		Products.Form.Checkbox.prototype.check.apply(this);
		Form.getFieldById("contactNumber").setRequired(true);

	},
	uncheck: function() {
		Products.Form.Checkbox.prototype.uncheck.apply(this);
		Form.getFieldById("contactNumber").setRequired(false);
	}
});
Products.Form.Checkbox.EmailSubscribe = Products.Form.Checkbox.extend({
	check: function() {
		Products.Form.Checkbox.prototype.check.apply(this);
		if (Form.getFieldById("email").required == false) {
			Form.getFieldById("email").setRequired(true);
		}
	},
	uncheck: function() {
		Products.Form.Checkbox.prototype.uncheck.apply(this);
		if (!Form.getFieldById("emailCopy").isChecked() ){
			Form.getFieldById("email").setRequired(false);
		}
	}	
});
/**
 * @class
 * @base Class
 * 
 * Provides styled Upload boxes, the technique used is rather complex and unweildy.
 * The elements the user sees are actually a regular text input and a button/link,
 * when the user mouseovers the button a hidden (opacity=0) file upload form item 
 * appears under their cursor (display=block rather than none) so that when the user clicks
 * they hit it rather than the link. The bounds checking in IE was missbehaving causing the upload
 * form to follow the user all around the screen so manual bounds chacking was added.
 * Hopefully this math is documented clearly enough to follow.
 */
Products.Form.Upload = new Class({
	initialize: function(element) {
		this.element = element;
		this.field   = element.getPrevious();
		this.file    = new Element("input", {"type": "file", "class": "hiddenFile"});
		//this.file    = new Element("input", {"type": "file"});
		this.file.name = this.field.name;
		this.field.removeAttribute("name");
		
		this.element.appendChild(this.file);
		
		this.file.addEvent("change", this.onChange.bind(this));
	
		this.element.addEvent("mouseenter", this.onMouseenter.bind(this));
		this.element.addEvent("mouseleave", this.onMouseleave.bind(this));
	},
	
	getName: function() {
		return this.file.name;
	},
	
	getValue: function() {
		return this.file.value;
	},
	
	onChange: function() {
		var fileExtension = this.file.value.substr(this.file.value.length-3,3);
		if(this.validateFileExtension(fileExtension)){
			this.field.value = this.file.value;
		}else{
			this.file.value = ""; 
			alert("Invalid file extension. Please attach a picture that is one of the following supported file types:"+
			"\n\t\t\t\t.jpg, .gif, .jpeg, .png, .bmp, .tif, .pdf");
		}
	},
	
	validateFileExtension: function(fileExtension){
		var validFileTypes = new Array ('jpg','gif','peg','png','bmp','tif','pdf','JPG','GIF','PEG','PNG','BMP','TIF','PDF');
		for (i = 0; i < validFileTypes.length; i++) {
    		 if (validFileTypes[i] == fileExtension) {
     		 	return true;
    		 } 
  		}
		return false;
	},
	
	onMouseenter: function() {
		this.file.setStyle("display", "block");
		this.element.addEvent("mousemove", this.onMousemove.bindAsEventListener(this));
	},
	
	onMouseleave: function() {
		this.file.setStyle("display", "none");
		this.element.removeEvents("mousemove");
	},
	
	onMousemove: function(event) {
		event = new Event(event);
		
		//Position of top/left of file field relative to cursor
		var fileOffset = {};
		fileOffset.x = this.file.getCoordinates().width - 10;
		fileOffset.y = this.file.getCoordinates().height+ 10;
		
		//Position (top/left) of file field's parent element within page
		var button = {};
		button.x = this.element.getPosition().x;
		button.y = this.element.getPosition().y;
		
		//size (h/w) of of button
		button.w = this.element.getSize().size.x
		button.h = this.element.getSize().size.y
		
		//because the hidden file input is a child if the 'button' IE has a hard time bounds checking, so we do it manually.
		if(
		   (button.x>event.page.x)           //left
		|| (button.x+button.w<event.page.x)  //right
		|| (button.y>event.page.y)           //top
		|| (button.y+button.h<event.page.y)  //bottom
		){
			this.onMouseleave();
		}
		
		// "real (top/left) upload box position relative to parent box" = 
		// "event's position in page" - "parents position in page" - "how far from the top left of our real upload field we wish to click"
		this.file.setStyle("left", event.page.x - button.x - fileOffset.x);
		this.file.setStyle("top",  event.page.y - button.y - fileOffset.y);
	}
});

/**
 * 
 * 
 * @param {Object} category
 * @param {Object} content
 */
Products.Omniture = {
	send: function(category, content) {
		s.currencyCode="AUD"	
		s.server=window.location.host;
		s.prop1="SD";
		s.prop2="Maps";
		s.prop3="Whereis";
		s.channel="Products";
		s.pageName=s.prop1+":"+s.prop2+":"+s.prop3+":"+s.channel;
		s.hier1=s.prop1+"|"+s.prop2+"|"+s.prop3+"|"+s.channel;
	
		if($defined(category)) {
			s.prop4=category;
			s.eVar4=s.prop4;
			s.pageName += ":" + category;
		}
		
		if($defined(content)) {
			s.prop5=content;
			s.eVar5=s.prop5;
			s.pageName += ":" + content;
			if($defined(category)) {
				s.hier1 +="|"+category;
			}
		}
		var omniture=s.t();
		if (omniture) {
			document.write(omniture);
		}
	}
};
// Does initialisation, declares global var 'Form'
(function(){
	var init = function(){
			Form ={};
		if ($("contactForm")) {
			Form = new Products.Form.Contact($("contactForm"));
		} else if ($("errorForm")) {
			Form = new Products.Form.Report($("errorForm"));
		}
	}
	
	if(window.ie) {
		window.addEvent("load", init);
	} else {
		window.addEvent("domready", init); 
	}
})();

Products.Subscription = new Class(
{
	/**
	 * Internal event handler for when the submit button (anchor) is clicked.
	 * This will construct a transmission object depending on the data entered
	 * in by the user. There is some user validation here as well.
	 *
	 * Once the transmission object is constructed, the handleSubscription or
	 * handleFeedback functions will be called.
	 *
	 * @member Products.Subscription
	 */
	handleSubmit: function(){
		this.transmission = null;
		
		// Subscription
		var email = $("email").value;
		var name = $("name").value;
				
		if (!this.transmission) {
			this.transmission = new Object();
			this.transmission.name = name;
			this.transmission.email = email;
			this.transmission.action = "subscribe";
		}
		
		if (this.transmission.email) {
				this.handleSubscription();
		}
	},
	
	/**
	 * Handles transmission to the the subscription servlet. JSON sent directly to
	 * the subscription servlet and the responses are all captured using inner functions.
	 *
	 * @member Products.Subscription
	 */
	handleSubscription: function() {
		var path = window.location.href.replace("/products/contact-us/","");
		this.subscriptionTransport = new Json.Remote(path + "/subscription?type=json", {
			onComplete: function(response) {
				this.subscriptionTransport = null;
				if(response.result == "error") {
					alert(response.message);
				}
			}.bind(this),
			onException: function(response) {
				this.subscriptionTransport = null;
				alert("Unable to complete subscription at this time, please try again later.");
			},
			onFailure: function(response) {
				this.subscriptionTransport = null;
				alert("Unable to complete subscription at this time, please try again later.");
			}.bind(this)
		}).send(this.transmission);
	}
});	