NUNALIIT_CONTRIBUTIONS = function($) {
	
	var contributionOptions = {
		db: null
		,putUrl: 'upload/put'
		,deleteUrl: 'contributions/delete'
		,table: 'contributions'
		,editFields: [ 'title', 'notes' ] // code specific to these fields exists to create the form
		,data: {}
		,title: ''
		,notes: ''
		,onSuccess: function(msg, textStatus){}
		,onError: function(xmlHttpRequest, textStatus, errorThrown){}
	};
	
	var index = 0;
	var dialog = null;
	var form = null;
	//var holder = null;

	function UserSubmit() {
		form.remove();
		form.css({display:"none",postion:"absolute",top:"0px",left:"0px"});
		//holder.append(form);
		$(document.body).append(form);
		dialog.jqmHide();

		var myForm = form;
		form = null;

		_SubmitForm(myForm);
	};

	function UserCancel() {
		dialog.jqmHide();
		if( form ) {
			form.remove();
			form = null;
		}
	};

	function _SubmitForm(myForm) {
		try {
			$(myForm).ajaxSubmit({
				beforeSubmit: BeforeFormSubmit
				,success: function(data,success){OnFormSuccess(data,success,myForm);}
				,error: function(xhr, status, e){OnFormError(xhr, status, e, myForm);}
				,iframe: true
			});
		} catch(error) {
			OnFormError(null, 'error', error, myForm);
		}
	};

	function _SubmitFormImmediate(options,form) {
		try {
			form.ajaxSubmit({
				success: function(data,success){ form.remove(); }
				,error: function(xhr, status, e){ form.remove(); }
				,iframe: true
			});
		} catch(error) {
			form.remove();
		};
	};
	
	function InstallKey(myForm,key) {
		$(myForm).attr("contributions-key",key);
		_SubmitForm(myForm);
	};

	function BeforeFormSubmit(parmArray,form,options) {
		var $form = $(form);
		
		var needKey = 1;
		
		if( ! $.progress ) {
			// There is no progress tracker, do not attempt
			// to get a key.
			needKey = 0;
		}
		
		var key = $form.attr("contributions-key");
		if( key ) {
			// There is a key, do not need to get one
			needKey = 0;
		}
		
		if( needKey ) {
			// Get key
			$.progress.getProgressKey(function(key){
				InstallKey(form,key);
			});
			
			// We need a key. Abort submitting.
			return false;
		}
		
		// At this point, we have a key or we do not need one
		if( key ) {
			$.progress.startProgressTrackingOn(key,'Submit contribution');
			
			$form.prepend('<input type="hidden" name="progressId" value="'+key+'"/>');
		};
		
		return true;
	};
	
	function OnFormSuccess(data, status, myForm) {
		//if( window.console && window.console.log ) window.console.log('OnCompletion',status,data);
		
		myForm.remove();
	};

	function OnFormError(xhr, status, e, myForm) {
		//if( window.console && window.console.log ) window.console.log('OnError',status,xhr,e);
		
		myForm.remove();
	};

//	function createHolder() {
//		if( !holder ) {
//			holder = $('<div style="position:absolute;top:0px;left:0px;display:none"></div>');
//			$(document.body).append(holder);
//		};
//	};

	function clearFileFields(oObj) {
		oObj.filename = null;
		oObj.original_filename = null;
		oObj.mimetype = null;
		oObj.file_size = null;
	}
	
	function createForm(options) {
		var fileDivName = '____contrib_fileDiv';
		var fileDeleteDivName = '____contrib_fileDeleteDiv';
		var deleteCBName = '___contrib_deleteCB';
		
		function insertFileReplaceDialog() {
			if (!options.data.deleteFile) {
				$('#'+fileDeleteDivName).html(
					'<span class="jqmContributions_input_heading">Replace attached file:</span>' +
						'<input class="jqmContributions_input" type="file" name="upload"/>');
			} else {
				$('#'+fileDeleteDivName).empty();
			}
		}
		
		function insertFileDiv() {
			var offerFileDelete = (typeof options.data.deleteFile != 'undefined');
			if (!offerFileDelete) { // no existing file - delete option not needed
				var htmlString = 
					'<span class="jqmContributions_input_heading">Attach file:</span>' +
						'<input class="jqmContributions_input" type="file" name="upload"/>';
			} else {
				var htmlString = 
					'<span class="jqmContributions_input_heading">Delete attached file:</span>' +
						'<input type="checkbox" id="' + deleteCBName + '"/>' +
					'<div id="' + fileDeleteDivName + '"></div>';
			}
			$('#'+fileDivName).html(htmlString);
			
			if (offerFileDelete) {
				insertFileReplaceDialog();
				
				$('#'+deleteCBName).click(function() {
					if ($('#'+deleteCBName).attr('checked')) {
						options.data.deleteFile = true;
						clearFileFields(options.data);
					} else {
						options.data.deleteFile = false;
					}
					insertFileReplaceDialog();
				});
			}
		}
		
		function isEditField(name) {
			for (var i=0; i<options.editFields.length; i++) {
				if (name == options.editFields[i]) {
					return(true);
				}
			}
			return(false);
		}
		
		function isFileDerivedField(name) {
			return(name == 'filename' ||
				name == 'mimetype' ||
				name == 'original_filename' ||
				name == 'file_size');
		}
		
		if( !form ) {
			var myIndex = index;
			++index;
			
			var hiddenData = '';
			for (var name in options.data) {
				if (!options.data.isUpdate || // these fields should not actually be there if not an update
						(!isEditField(name) &&
						 !isFileDerivedField(name) &&
						 name != 'deleteFile' &&
						 name != 'fileuse')) {
					var value = options.data[name];
					hiddenData += '<input type="hidden" name="'+name+'" value="'+value+'"/>';
				}
			};
			
			// The name attributes in the form SHOULD MATCH the db schema column names
			// otherwise the server side has to contain hacks to translate it.  Use
			// whatever terminology you want in the accompanying label spans.  See 
			// comment/notes for example: the default db column name is notes but 
			// comment is used on the web form.
			var inputs = 
				'<p class="jqmContributions_instructions">' +
					'Contribute information about this place to the atlas. ' +
					'Your contribution will appear along with other comments about ' +
					'this place shown in the side panel. You can also upload ' +
					'an audio recording, video or images about the place.' +
				'</p>' +
				'<p class="jqmContributions_instructions">' +
					'If you proceed you will ' +
					(options.data.isUpdate ?
						'<i>UPDATE the following comment</i>.' :
						'<i>ADD a new comment</i>.') +
				'</p>' +
				'<p>' +  
					'<span class="jqmContributions_input_heading">Comment title:</span>' +
						'<input class="jqmContributions_input" type="text" name="title"/><br/>' +
					'<span class="jqmContributions_input_heading">Comment:</span>' +
						'<textarea class="jqmContributions_input" name="notes" cols="50" rows="10"></textarea><br/>' +
					'<div id="' + fileDivName + '"></div>' +
				'</p>' +
				'<p>' +
					'<input class="jqmContributions_input" id="contributionSubmit_'+myIndex+'" ' +
						'type="button" value="Submit"/>' +
					'<input class="jqmContributions_input" id="contributionCancel_'+myIndex+'" ' +
						'type="button" value="Cancel"/><br/>'
				'</p>';
			
			var formId = 'contributionForm_'+myIndex;
			form = $('<form id="'+formId+'" action="'+options.putUrl+'" method="post" enctype="multipart/form-data">'+hiddenData+inputs+'</form>');
			$(dialog).append(form);
			insertFileDiv();
			
			if (options.data.isUpdate) { // fill the editable fields
				for (var i=0; i<options.editFields.length; i++) {
					var efName = options.editFields[i];
					$('#'+formId+' [name="'+efName+'"]').val(options.data[efName]);
				};
			};

			$('#contributionSubmit_'+myIndex).click(function(evt){
				if (typeof options.data.deleteFile != 'undefined' && options.data.deleteFile) {
					$('#'+formId).append('<input type="hidden" name="deleteFile" value="'+options.data.deleteFile+'"/>');
					$('#'+formId).append('<input type="hidden" name="fileuse" value=""/>'); // also clear the file use flag if deleting a file
				} else {
					$('#'+formId).append('<input type="hidden" name="fileuse" value="'+
						(typeof options.data.fileuse == 'undefined' ? '' : options.data.fileuse) +'"/>');
				}
				UserSubmit();
			});
			$('#contributionCancel_'+myIndex).click(function(evt){
				UserCancel();
			});
		}
	};
	
	function createHiddenForm(options) {
		var form = $('<form action="'+options.putUrl+'" method="post" enctype="multipart/form-data"></form>');
		
		var title = $('<input type="hidden" name="title"/>');
		form.append(title);
		title.attr('value',options.title);
		
		var notes = $('<input type="hidden" name="notes"/>');
		form.append(notes);
		notes.attr('value',options.notes);

		for(var name in options.data) {
			var value = options.data[name];

			var data = $('<input type="hidden" name="'+name+'"/>');
			form.append(data);
			data.attr('value',value);
		};
		
		return form;
	};
	
	function createDialog(options) {
		if( !dialog ) {
			dialog = $('<div class="jqmWindow"></div>');
			$(dialog).jqm();
			$(document.body).append(dialog);
		}
		
		createForm(options);
	};

	return {
		acceptsContribution: function(options_) {
			var options = $.extend({}, contributionOptions, options_);
			
			options.data.isUpdate = false;
			createDialog(options);
			$(dialog).jqmShow();
		}
		,acceptsContributionUpdate: function(options_) {
			var options = $.extend(true, {}, contributionOptions, options_);
			
			function setFileFields(offerDelete) {
				clearFileFields(options.data);
				if (offerDelete) {
					// by default, don't delete existing file but this will
					// cause the option to be offered.
					options.data.deleteFile = false;
				}
			}
			
			options.data.isUpdate = true;
			if (typeof options.data.filename != 'undefined' &&
				options.data.filename != null) {
				// for update - clear existing file fields.  Offer options to 
				// allow addition (if no file exists now) or delete/replace
				// if a file does exist.
				if (options.data.filename != '') {
					setFileFields(true);
				} else {
					setFileFields(false);
				}
			} else {
				setFileFields(false);
			}
			
			createDialog(options);
			$(dialog).jqmShow();
		}
		,deleteContribution: function(options_) {
			var options = $.extend({}, contributionOptions, options_);
			
			$.ajax({
				type: 'GET'
				,url: options.deleteUrl
				,data: options.data
				,dataType: 'json'
				,async: true
				,success: options.onSuccess
				,error: options.onError
			});
		}
		,addContribution: function(options_) {
			var options = $.extend({}, contributionOptions, options_);
			
			options.data.isUpdate = false;
			var form = createHiddenForm(options);
			$(document.body).append(form);
			_SubmitFormImmediate(options,form);
		}
	};
}(jQuery);
