var Upload = function(){
	
	return {
		
		done : {},
		
		count : {},
		
		name : {},
		
		checkDelay : 500, // in milliseconds
		
		loadTimeout : 600, // in seconds
		
		inputSelector : "input[type=file]",
		
		fileInputName : "data[#{model}][#{field}]",
		
		showStatusBar : false,
		
		rootUrl : "/",
		
		statusUrl : "#{root}catalysts/upload/#{apc}",
		
		uploadUrl : "#{root}catalysts/upload/",
		
		spinnerSrc : "#{root}img/upload/spinner.gif",
		
		model : "Upload",
		
		field : "file",
		
		timeoutMessage: "Failed. Upload timed out.",
		
		changeLabel: "Change to #{label}.",
		
		formTemplate : "" + "\n" +
		"	<form target=\"data_iframe_#{id}\"" + "\n" +
		"		id=\"Asynch_#{id}\"" + "\n" +
		"		enctype=\"multipart/form-data\"" + "\n" +
		"		method=\"post\"" + "\n" +
		"		action=\"#{url}\"" + "\n" +
		"		style=\"display:none;\"" + "\n" +
		"	>" + "\n" +
		"		<input name=\"_method\" value=\"POST\" type=\"hidden\" />" + "\n" +
		"		<input name=\"#{status}\" value=\"#{apc}\" id=\"Apc_#{id}\"type=\"hidden\" />" + "\n" +
		"		<input name=\"data[#{model}][#{field}][form_id]\" value=\"#{id}\" id=\"AsynchFile_#{id}\" type=\"hidden\">" + "\n" +
		"	</form>" + "\n" +
		"	<iframe src=\"about:blank\" style=\"display:none;\" id=\"data_iframe_#{id}\" name=\"data_iframe_#{id}\"></iframe>" + "\n" +
		"",
		
		statusTemplate : "" + "\n" +
		"	<img id=\"spinner#{id}\" src=\"#{src}\" class=\"spinner\" style=\"display:none;\" />" + "\n" +
		"	<div id=\"status#{id}\">&nbsp;</div>" + "\n" +
		"",
		
		waitAndCheckStatus : function(id){
			setTimeout("Upload.checkStatus('" + id + "');",Upload.checkDelay);
		},
		
		checkStatus : function(id) {
			
			var key = "status" + id;
			
			var spinner = jQuery("#spinner" + id);
			
			// Stop checking when upload is done.
			if( Upload.done[key] ){
				if(spinner) spinner.hide();
				Upload.done[key] = false;
				return true;
			}
			
			Upload.count[key] = (parseInt(Upload.count[key]) + 1);
			
			// Stop checking if we've passed the max execution time of the upload script 
			var max_checks = Math.floor( ((Upload.loadTimeout * 1000) / Upload.checkDelay) );
			
			if(max_checks > 0 && Upload.count[key] > max_checks ){
				jQuery("#"+key).text(Upload.timeoutMessage);
				return false;
			}
			
			// Don't show spinner if progress bar is enabled.
			if(spinner) spinner.hide();
			
			var apcField = jQuery("#Apc_" + id);
			var apc = apcField.val();
			
			jQuery.ajax({
				url: Upload.statusUrl.interpolate({root: Upload.rootUrl, id: id, apc: apc}),
				context: jQuery("#"+key),
				error: function(data){
				},
				success: function(data){
					
					var key = "status" + id;
					
					if( !Upload.done[key]){
						Upload.waitAndCheckStatus(id);
					}
				}
			});
		},
		
		setDone : function(id, data) {
			
			var key = "status" + id;
			
			var spinner = jQuery("#spinner" + id);
			if(spinner) spinner.hide();
			
			Upload.done[key] = true;
			
			// Set a message in the status field for this input.
				var statusField = jQuery("#"+key);
				if(statusField.length){
					statusField.html(data.message);
				}
			
			// Locate action dropdown and add option with value="change" and label = "Replace this X with " + data.label
			// If the change option already exists, update the existing one instead.
			// Get "Replace this X with " by finding the "replace" option in the dropdown and replacing "with ..." in
			// that option's value with "with " + data.label
			var action = jQuery("#"+id + "_action");
			
				if(action){
					
					var label = "Update to " + data.label;
					
					var lastOption = action.find("option").last();
					
					if(lastOption.val() != "change"){
						
						action.append("<option value='change'>" + label + "</option>");
						
					}else{
						
						lastOption.text(label);
						
					}
					
					// Select last input
					action.find("option").last().attr("selected", "selected");
					
					// Locate action dropdown and insert hidden "target" field before it with value of data.target
					// If the "target" field already exists, update the existing one instead.
					
						var target = jQuery("#"+id + "_target");
						if(target.length > 0){
							target.val( data.target );
						}else{
							var targetInput = "<input type='hidden' class='hidden' id='" + id + "_target' name='" +Upload.name[key] + "[target]' value='" + data.target + "' />";
							action.before(targetInput);
						}
					
				}
			
			// Add the file input back into the original form.
				var f = jQuery("#"+id);
				f.attr("name", Upload.name[key]);
				
				var fileInput = "<input type='file' class='" + f.className + "' id='" + id + "' name='" +Upload.name[key] + "' />";
				
				f.remove();
				statusField.before( fileInput );
				
				Upload.addOnChange(id);
				
			// Update the src or href of the change image or link
				var change = jQuery("#"+id+"_change_display");
				if(change){
					
					switch(change.attr("tagName")){
					case 'IMG':
					case 'img':
						change.attr("src", data.href);
						change.attr("alt", Upload.changeLabel.interpolate({label: data.label}));
						break;
					case 'A':
					case 'a':
						change.attr("href", data.href);
						change.text(Upload.changeLabel.interpolate({label: data.label}));
						break;
					}
				}
				
			// Show the action dropdown and hide the file input if there are multiple available actions.
				if(action){
					action.show();
					jQuery("#"+id).hide();
				}
				var func = eval("change_file_"+id);
				if(typeof(func) == "function"){
					func();
				}
				
			
		},
		
		addOnChange : function(id){
			jQuery("#"+id).change(function(event){
				var element = jQuery(this);
				var id = element.attr("id");
				
				element.attr("name", Upload.fileInputName.interpolate({model: Upload.model, field: Upload.field}));
				
				var otherForm = jQuery("#Asynch_" + id);
				var otherField = jQuery("#AsynchFile_" + id);
				
				otherField.after( element );
				
				// Set timeout to update status bar if APC is enabled or show a spinner
				if(Upload.showStatusBar){
					Upload.waitAndCheckStatus(id);
				}else{
					var spinner = jQuery("#spinner" + id);
					if(spinner) spinner.show();
				}
				
				otherForm.submit();
				
				return false;
				
			});
		},
		
		init : function () {
			
			jQuery(Upload.inputSelector).each(function(){
				var id = jQuery(this).attr("id");
				
				var key = "status" + id;
				
				if( id && typeof(Upload.name[key]) == "undefined" ){
					Upload.initialize(id);
				}
			});
		},
		
		initialize: function(id){
			
			var f = jQuery("#"+id);
			var body = jQuery("body").first();
			
			var key = "status" + id;
			
			Upload.done[key] = false;
			Upload.count[key] = 0;
			Upload.name[key] = f.attr("name");
			
			var apc = 'tracking_id_' + ((1 + Math.random())+"").replace(/\./,'');
			
			var url = Upload.uploadUrl.interpolate({root: Upload.rootUrl, id: id, apc: apc});
			
			var src = Upload.spinnerSrc.interpolate({root: Upload.rootUrl, id: id, apc: apc});
			
			var status = "";
			if(Upload.showStatusBar == "apc"){
				status = "APC_UPLOAD_PROGRESS[]";
			}else if(Upload.showStatusBar == "uploadprogress"){
				status = "UPLOAD_IDENTIFIER";
			}
			
			body.append( Upload.formTemplate.interpolate({
				id: id,
				apc: apc,
				url: url,
				status: status,
				root: Upload.rootUrl,
				model: Upload.model,
				field: Upload.field
			}) );
			
			f.before( Upload.statusTemplate.interpolate({
				src: src,
				id: id,
				apc: apc,
				root: Upload.rootUrl,
				model: Upload.model,
				field: Upload.field
			}) );
			
			var otherForm = jQuery("#Asynch_" + id);
			var otherField = jQuery("#AsynchFile_" + id);
			
			Upload.addOnChange(id);
			
		},
		
		settings : function(obj){
			for (var key in obj) {
				Upload[key] = obj[key];
			}
		}
		
	};
}();

if(typeof(UploadSettings) != "undefined"){
	// Use custom settings if provided
	Upload.settings(UploadSettings);
}

jQuery(document).ready( function(){
	Upload.init();
});

