/**
 * 
 * 
 * ---------------------------------------------------------------------------
 * 
 * Copyright (C) 2009 Omnium Research Group
 * 
 * ---------------------------------------------------------------------------
 * 
 * LICENSE:
 * 
 * This file is part of Omnium(R) Software.
 * 
 * Omnium(R) Software is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * Omnium(R) Software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Omnium(R) Software; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 * 
 * ---------------------------------------------------------------------------
 * 
 * @author    Dan Callaghan <dan@omnium.net.au>
 * @author    Andrew Morrison <andrew@omnium.net.au>
 * @copyright 2009 Omnium Research Group
 * @license   http://www.gnu.org/licenses/gpl.txt GNU GPL v2
 * @link      http://open.omnium.net.au Omnium Open
 **/



var omForm = {};

omForm = Class.create();
omForm.prototype = {
	initialize: function(formId, submitButtonId, uploadProgressId, activeImg, fileInputs, multipleFileInputs, focusTarget)
	{
		// Initialise the form object
		this.formObj = $(formId);
		
		// Set the IDs of the submit button and upload progress
		this.submitButton = $(submitButtonId);
		this.uploadProgress = $(uploadProgressId);
		
		// Check to see if an active image has been specified
		if (activeImg) {
			// Initialise the active background image
			this.activeImg = 'url(' + activeImg + ')';
		}
		
		// Initialise an array of any file inputs for Safari hack
		this.fileInputs = fileInputs;
		this.multipleFileInputs = multipleFileInputs;
		
		// Add a submit event listener to the form
		Event.observe(this.formObj, 'submit', this.submit.bindAsEventListener(this));
		
		if (this.activeImg) {
			
			this.bindFocusListener();
			
		}
		
		// Add event listeners for submit button
		Event.observe(this.submitButton, 'mouseover', this.hover.bindAsEventListener(this));
		Event.observe(this.submitButton, 'mouseout', this.hover.bindAsEventListener(this));
		
		if (focusTarget) {
			if (focusTarget != 'none') {
				focusTarget = $(focusTarget);
			} else {
				focusTarget = false;
			}
		} else {
			// Find the first form element
			focusTarget = this.formObj.firstDescendant().getElementsBySelector('input', 'select', 'textarea')[0];
		}
		
		if (focusTarget) {
			focusTarget.focus();
		}
	},
	
	bindFocusListener: function() {
		// Traverse through the immediate descendants of the form
		formElements = this.formObj.getElementsBySelector('input', 'select', 'textarea');
		elemSize = formElements.size();
		for (var f = 0; f < elemSize; f++) {
			// Add event listeners to the form elements
			Event.observe(formElements[f], 'focus', this.focus.bindAsEventListener(this));
			Event.observe(formElements[f], 'blur', this.blur.bindAsEventListener(this));
		};
	},
	
	// Gives focus to a form element div
	focus: function(e)
	{
		// Initialise the form element object variable
		var formElementObj;
		
		// Check whether we are dealing with an event
		if (e.target) {
			formElementObj = e.target;
		} else {
			formElementObj = e;
		}
		
		// Set the current element as active
		divObj = formElementObj.up('.omFormContainer');
		divObj.setStyle({backgroundImage: this.activeImg});
		
		if (this.activeObj) {
			
			if (this.activeObj != divObj) {
				// Set the active object as inactive and set the new active object
				this.activeObj.setStyle({backgroundImage: 'none'});
			}
			
		}
		
		this.activeObj = divObj;
	},
	
	// Blurs a form element div
	blur: function(e)
	{
		divObj = e.target.up('.omFormContainer');
		divObj.setStyle({backgroundImage: 'none'});
	},
	
	// Sets the focus for a specific element
	setFocus: function(formElement)
	{
		tabElement = $(formElement).up('.tab');
		if (tabElement) {
			if (!tabElement.visible()) {
				tabElement.show();
			}
		}
		$(formElement).activate();
	},
	
	// Deals with hovering of the submit button
	hover: function(e)
	{
		if (e.type == 'mouseover') {
			e.target.setStyle({backgroundPosition: '0 -17px'});
		} else {
			e.target.setStyle({backgroundPosition: '0 0'});
		}
	},
	
	// A function which executes when the form is submitted
	submit: function(e)
	{
		
		if (this.uploadProgress) {
			// Hide the submit button and show the upload progress meter
			this.submitButton.hide();
			this.uploadProgress.show();
		}
		
		// Workaround for Safari not upload files which are hidden
		if (this.fileInputs) {
			for (var i = 0; i < this.fileInputs.length; i++) {
				if (!$(this.fileInputs[i]).visible()) {
					$(this.fileInputs[i]).setStyle({
						display: 'block',
						position: 'absolute',
						left: '-9999px'
					});
				}
				if (this.multipleFileInputs) {
					$(this.fileInputs[i]).immediateDescendants().each(
						function (fileInputObj) {
							if (!fileInputObj.visible()) {
								fileInputObj.show();
								fileInputObj.setStyle({
									display: 'block',
									position: 'absolute',
									left: '-9999px'
								});
							}
						}
					);
				}
			};
		}
		
	}
	
}


omForm.ErrorChecker = Class.create();
omForm.ErrorChecker.prototype = {
	initialize: function(errorArray, messageArray, errorSrc, errorBubble, multiUpload)
	{
		
		// Initialise the array of element id with an error
		this.errorArray = errorArray;
		
		// Initialise the corresponding messages
		this.messageArray = messageArray;
		
		// Initialise the error icon image source
		this.errorSrc = errorSrc;
		
		// Whether this upload is on of multiple - multiple uploads require the error be sent to the parent page.
		this.multiUpload = multiUpload;
		
		if (errorBubble) {
			// Initialise the error bubble image source
			this.errorBubble = 'url(' + errorBubble + ')';
		}
		
		this.createMessages();
	},
	
	createMessages: function()
	{
		// Initialise an error icon for later use
		var eIconObj = new Element('img', { src: this.errorSrc, className: 'errorIcon' });
		
		// Traverse through the error elements
		for (var i = 0, eLen = this.errorArray.length; i < eLen; ++i) {
			
			// Extend our current error object
			var e = $(this.errorArray[i]);
			
			// Check for associated subtab
			var subtabObj = e.up('.subtabs');
			
			// Check for associated tab
			var tabObj = e.up('.tab');
			
			// Initialise the class name
			var errorClass = 'formError';
			
			// Check for narrow class name
			if (e.hasClassName('narrow')) {
				errorClass += ' narrow';
			}
			
			if (subtabObj) {
				// Find the file number
				var fileNum = 'File ' + e.up('.imageContainer').id.split("_")[1] + ': ';
				
				// Build the error message for our subtab
				var eIcon = eIconObj.cloneNode(true);
				var eSubMessage = new Element('p', { className: errorClass });
				
				// Create the message element. Consists of Icon + Message inside of a paragraph element
				var E = eSubMessage.insert(eIcon).insert(fileNum + this.messageArray[i]);
				
				subtabObj.insertBefore(E, subtabObj.firstDescendant());
			}
			
			// Build the error message for our tab
			var eIcon = eIconObj.cloneNode(true);
			var eMessage = new Element('p', { className: errorClass });
			
			// Create the message element. Consists of Icon + Message inside of a paragraph element
			var E = eMessage.insert(eIcon).insert(this.messageArray[i]);
			
			// In the case of a multiple upload form, send the error to the parent page to be displayed.
			if (this.multiUpload) {
				parent.form.showUploadResult(E, true);
				parent.form.uploadError = true;
			} else {
			
				if (this.errorBubble) {
					// Set the current element as active
					divObj = e.up('.omFormContainer').setStyle({ backgroundImage: this.errorBubble });
				}
			
				// Get our container object and insert the new error message element (E) into our current error element (e)
				containerObj = e.parentNode;
				containerObj.insertBefore(E, e);
			}
		}
		
	}
}

// For forms that handle multiple uploads
var omUploadForm = Class.create(omForm, {
	initialize: function($super, sVars, pageSettings, formVars, resultVars)
	{
		// Instantiate the omForms super
		$super(sVars[0], sVars[1], sVars[2], sVars[3], sVars[4], sVars[5], sVars[6]);
		
		// Instantiate the list of forms to upload on a submit.
		this.uploadList			= new Array();
		
		// Instantiate internal markers that reference how many files have been added to the upload list, and how many have been removed
		this.uploadMarker		= 0;
		this.removedMarker		= 0;
		
		// Reference the form container to append multiple upload forms to and the form id for cloning
		this.formContainer		= this.formObj.parentNode;
		this.formId				= sVars[0];
		
		// As forms are submitted in order, the current form needs to be referenced
		this.currentFormObj		= null;
		
		// Instantiate the live upload errors variables - keep track of errors in the last submitted form, and across all forms
		this.fileErrors			= false;
		this.uploadError		= false;
		
		// Project settings - maximum uploads - default to 5 otherwise
		this.maxUploads			= pageSettings[0];
		this.redirectLocation	= pageSettings[1];
		
		// Button Elements
		this.submitObj			= $(formVars[0]);
		this.newUploadObj		= $(formVars[1]);
		// Button container
		this.buttonContainer	= $(formVars[2]);
		
		// Required Form Elements
		this.requiredFields		= formVars[3];
		// The tab name fields - used in instantiating the form tabs on a form clone
		this.tabFields			= formVars[4];
		
		// Progress icon
		this.progressSrc		= resultVars[0];
		// Success result icon
		this.successSrc			= resultVars[1];
		// Form error icon
		this.errorSrc			= resultVars[2];
		
		this.formContainer		= this.formObj.parentNode;
		
		// Event listeners for cloning the upload form to add a new file, and submitting all forms - attached to relevent buttons.
		Event.observe(this.newUploadObj, 'click', this.cloneUploadForm.bindAsEventListener(this));
		Event.observe(this.submitObj, 'click', this.submitForms.bindAsEventListener(this));
	},
	
	cloneUploadForm: function() {
		// Check for input
		if(!this.checkForInput(false)) {
			parent.omFormBox.set(null,0);
			return;
		}
		
		if (this.uploadMarker - this.removedMarker <= this.maxUploads) {
			var newFormObj 			= this.formObj.cloneNode(false);
			newFormObj.innerHTML 	= this.formObj.innerHTML;
			
			this.makeUniqueElements(this.formObj);
			this.pushFormValueToList();
			this.formContainer.insertBefore(newFormObj, this.buttonContainer);
			
			this.formObj.setStyle({display: 'none'});
			this.formObj = newFormObj;
			this.bindFocusListener();
			this.clearInputData(this.formObj);
			
			parent.omFormBox = new omFormWidgets.FormBox(
				'formBoxTabs',
				0,
				[
					[
						'omFileInput',
						this.tabFields[0],
						null
					],
					[
						'descriptionBox',
						this.tabFields[1],
						null
					]
				],
				'parent.form.focus(this);'
			);
			
			if (this.uploadMarker - this.removedMarker == 0) {
				this.toggleFileList(true);
			}
			
			this.uploadMarker++;
			
			if (this.uploadMarker - this.removedMarker == this.maxUploads) {
				// Disable the clone button
				this.newUploadObj.disable = true;

				new Effect.BlindUp(this.formObj, { duration: 0.2 });
				new Effect.BlindUp($('newFilesContainer'), { duration: 0.2 });

				// Create a new error message to alert the user to the maximum number of files allowed to be uploaded at a time.
				var listContainer	= $('omUploadList');
				var eIconObj 		= new Element('img', { src: this.errorSrc, className: 'errorIcon' });
				var err 			= new Element('p', { className: 'formError' });
				err.insert(eIconObj).insert('Maximum ' + this.maxUploads + ' Uploads');
				listContainer.appendChild(err);
			}
		}
	},
	
	
	pushFormValueToList: function() {
		var listContainer	= $('omUploadContent');
		var listObj			= new Element('div', { id: 'omUploadList_' + this.uploadMarker , className: 'uploadContent' });
		var leftElem		= new Element('span', { id: 'omUploadName_' + this.uploadMarker , className: 'left' });
		var rightElem		= new Element('span', { id: 'omUploadAction_' + this.uploadMarker , className: 'right' });
		var removeElem		= new Element('a', { id: 'removeForm_' + this.uploadMarker });
		
		// Remove the directory structure out of the file name (IE6&7), and then insert it into the list
		var itemName = $('fileUpload_' + this.uploadMarker).value;
		var nameIndex = itemName.lastIndexOf('\\') + 1;
		
		if (nameIndex > 0 && nameIndex < itemName.length) {
			itemName = itemName.substr(nameIndex);
		}
		
		leftElem.insert(itemName);
		removeElem.insert(omVars.get('remove_item'));
		rightElem.insert(removeElem);
		
		listObj.insert(leftElem).insert(rightElem);
		listContainer.appendChild(listObj);
		
		$('fileCount').innerHTML = ' - ' + (1 + this.uploadMarker - this.removedMarker) + ' ' + omVars.get('item_name');
		
		Event.observe(removeElem, 'click', this.removeFileForm.bindAsEventListener(this, this.uploadMarker));
	},
	
	// Check to see if required fields have enough data to continue an operation
	checkForInput: function(submit) {
		var emptyForm = 0;
		var returnValue = true;
		this.clearErrorMessages();
		
		// If the for
		for (var i = 0; i < this.requiredFields.length; i++) {
			// Get the next required field in the form and trim
			var requiredElem = this.formContainer.down('[id=' + this.requiredFields[i] + ']');
			var valueTrimmed = requiredElem.value.replace(/^\s+|\s+$/g, '');
			
			// If a required field is blank, insert an error message, and update the return value to halt progress on actions
			if (valueTrimmed == undefined || valueTrimmed == '') {
				var eIconObj = new Element('img', { src: this.errorSrc, className: 'errorIcon' });
				var err = new Element('p', { className: 'formError' });
				err.insert(eIconObj).insert(omVars.get('required_field'));
				requiredElem.parentNode.insertBefore(err,requiredElem);
				returnValue = false;
				emptyForm++;
			}
		}
		
		// On a submit, if the form is empty (doesn't have ANY required fields) then ignore it and hide the form.
		if (submit && emptyForm == this.requiredFields.length) {
			returnValue = true;
			this.clearErrorMessages();
			new Effect.BlindUp($(this.formObj), { duration: 0.2 });
			new Effect.BlindUp($(this.buttonContainer), { duration: 0.2 });
		} else if (submit && returnValue) {
			// If the form has all required fields on a submit, then push the form to the list and hide the form.
			this.makeUniqueElements(this.formObj);
			this.pushFormValueToList();
			new Effect.BlindUp($(this.formObj), { duration: 0.2 });
			new Effect.BlindUp($(this.buttonContainer), { duration: 0.2 });
		}
		
		return returnValue;
	},
	
	// Remove all form errors
	clearErrorMessages: function() {
		var pageErr = $$('p.formError');
		for (var i = 0; i < pageErr.length; i++) {
			pageErr[i].remove();
		}
	},
	
	// Internet Explorer includes input and textarea data when copying the innerHTML of a form - for a blank new form, it needs to be cleared.
	clearInputData: function(elem) {
		var children = elem.childElements();
		for (var i = 0; i < children.length; i++) {
			this.clearInputData(children[i]);
		}
		if (elem.tagName == 'INPUT' || elem.tagName == 'TEXTAREA') {
			elem.setAttribute('value','');
		}
	},
	
	// The filelist can be toggled by the user. This ensures the filelist is in a chosen state.
	toggleFileList: function(openState) {
		if (openState && !$('omUploadContent').visible()) {
			parent.rollover.swap();
		} else if (!openState && $('omUploadContent').visible()) {
			parent.rollover.swap();
		}
	},
	
	// Remove a file from the file upload list
	removeFileForm: function(e) {
		var args = $A(arguments);
		var removeId = args[1];
		if (typeof removeId == 'number') {
			$(this.formId + '_' + removeId).remove();
			$('omUploadList_' + removeId).remove();
			
			// Re-enable the clone button
			this.newUploadObj.disable = false;
			
			this.removedMarker++;
			$('fileCount').innerHTML = ' - ' + (this.uploadMarker - this.removedMarker) + ' file/s';
			this.clearErrorMessages();
			
			// If we've removed the last file from the file upload list, close it
			if (this.uploadMarker - this.removedMarker == 0) {
				this.toggleFileList(false);
			} else if (this.uploadMarker - this.removedMarker == this.maxUploads - 1) {
				// If the maximum number of uploads was reached, and we've cleared list space, re-enable the form
				new Effect.BlindDown(this.formObj, { duration: 0.2 });
				$('newFilesContainer').show();
			}
		}
	},
	
	// Give a form unique ids
	makeUniqueElements: function(elem)
	{
		var children = elem.childElements();
		for (var i = 0; i < children.length; i++) {
			this.makeUniqueElements(children[i]);
		}
		if (elem.id) {
			elem.setAttribute('id',elem.id + '_' + this.uploadMarker);
		}
	},
	
	// Get a list of all forms with content to submit.
	submitForms: function()
	{
		// Checks for viable form input on the last form. If it's empty, it will be ignored.
		if (!this.checkForInput(true)) {
			return;
		}
		// Disable the buttons
		this.submitObj.stopObserving('click');
		this.newUploadObj.stopObserving('click');
		
		// Take away the 'remove' actions
		this.toggleFileList(true);
		var list = $$('span.right');
		//list.each(function(elem) { elem.innerHTML = ' '; } );
		
		var inputFiles = new Array();
		// Find forms with content to submit (effectively ignores empty forms)
		for (var i = 0; i < document.forms.length; i++) {
			var formInputs = document.forms[i].getElementsByTagName('input');

			for (var j = 0; j < formInputs.length; j++) {
				if (formInputs[j].type == 'file' && formInputs[j].value != undefined && formInputs[j].value != '') {
					inputFiles.push(document.forms[i].id);
					break;
				}
			}
		}

		this.uploadList = inputFiles;
		this.submitForm();
	},
	
	// Submit the top form from the list of forms to submit
	submitForm: function() {
		if (this.uploadList.length < 1) {
			if (this.fileErrors) {
				// Give the option of going back to upload page, or continuing back to gallery
				var msg			= omVars.get('upload_error');
				var gotoGallery = omVars.get('gallery_return');
				var seeErrors   = omVars.get('error_inspect');
				
				Alert.fire(
					msg,
					'galleryalert_logo.png',
					gotoGallery,
					'arrow_right.png',
					this.redirectLocation,
					seeErrors,
					'arrow_left.png'
				);
			} else {
				// All forms submitted without error
				document.location = this.redirectLocation;
			}
			return;
		}
		
		// Get the next form in the list
		var currentForm = this.uploadList.shift();
		var submitForm = $(currentForm);
		
		if (submitForm && submitForm.tagName == 'FORM') {
			this.currentFormObj = submitForm;
			
			// Find the 'remove' action assigned to this form and replace it with a progress icon
			try {
				var containerIDIndex = this.currentFormObj.id.lastIndexOf('_');
				var containerID = this.currentFormObj.id.substr(containerIDIndex);
				var containerName = 'omUploadAction' + containerID;
				var container = document.getElementById(containerName.toString());
				container.innerHTML = '';
				container.insert(new Element('img', { src: this.progressSrc, className: 'errorIcon' }));
			} catch (err) {}
			
			var targetName = currentForm + '_upload';
			var uploadTarget = document.createElement('DIV');
			// submit the form to a hidden iFrame so as not to reload the page and lose unsubmitted forms
			uploadTarget.innerHTML = 
			'<iframe style="position: absolute; top: -9999px;" src="#" id="' + targetName + '" name="' + targetName + '" onload="parent.form.uploadHandle();"></iframe>';
			document.body.appendChild(uploadTarget);

			submitForm.target = targetName;
			submitForm.submit();
			
		} else {
			// If the form was removed before an upload could happen, continue on to the next form
			this.submitForm();
		}
	},
	
	// Find the current form status area and insert an upload success message
	showUploadResult: function(showError, error) {
		try {
			var containerIDIndex = this.currentFormObj.id.lastIndexOf('_');
			var containerID = this.currentFormObj.id.substr(containerIDIndex);
			var containerName = 'omUploadAction' + containerID;
			var container = document.getElementById(containerName.toString());
			container.innerHTML = '';
			if (error) {
				container.insert(showError.innerHTML);
				this.fileErrors = true;
			} else {
				container.insert(new Element('img', { src: this.successSrc, className: 'errorIcon' })).insert(omVars.get('upload_success'));
			}
		} catch (err) {}
	},
	
	// If an error wasn't returned from the target iframe, indicate that the upload was successful and continue through the list
	uploadHandle: function()
	{
		if (!this.uploadError) {
			this.showUploadResult(null, false);
		} else {
			this.uploadError = false;
		}

		// After showing the result, submit the next form
		this.submitForm();
	}
});

// Gets the associated timezones when a user's location is changed
function getTimezones(locationSelect, timezoneSelect, current, ajaxFile)
{
	var location = locationSelect.options[locationSelect.options.selectedIndex].value;
	var params = 'location=' + encodeURIComponent(location);
	params += '&current=' + encodeURIComponent(current);
	
	new Ajax.Updater(
		timezoneSelect,
		ajaxFile,
		{ parameters:params }
	);
}