(function($){
	
    $.UploadDialog = function(el, options){
        // To avoid scope issues, use 'base' instead of 'this'
        // to reference this class from internal events and functions.
        var base = this;
        
        // Access to jQuery and DOM versions of element
        base.$el = $(el);
        base.el = el; 

		base.uuid = null;
		base.timer = null;
		base.xhr = null;
		base.action = null;
        
        // Add a reverse reference to the DOM object
        base.$el.data("UploadDialog", base);
        
        base.init = function(){
            base.options = $.extend({},$.UploadDialog.defaultOptions, options);
			
			base.setupOverlayAndFrame();
			base.setupContent();
			base.setupProgressBar();
			base.setupActions();
        }

		base.setupOverlayAndFrame = function(){
			base.$overlay = $("<div class='overlay' style='display:none'></div>").appendTo(document.body);
			base.$shadow = $("<div class='uploader-mask' style='display:none'></div>").appendTo(document.body);
			base.$frame = $("<div class='uploader' style='display:none'></div>").appendTo(document.body);
		}
		
		base.setupContent = function(){
			base.$title = $("<h2>" + base.options.title + "</h2>").appendTo(base.$frame);
			
			base.prepareForm().appendTo(base.$frame);
		}
		
		base.setupActions = function(){
			base.$actions = $("<div class='uploader-actions'></div>").appendTo(base.$frame);
			
			base.$begin = $("<a href='#' class='button'>" + base.options.actionLabel + "</a>").click(function(e){
				base.beginUpload();
				e.preventDefault();
			}).appendTo(base.$actions);
			
			$("<span> or </span>").appendTo(base.$actions);
			
			base.$cancel = $("<a href='#'>" + base.options.cancelLabel + "</a>").click(function(e){
				base.hide();
				e.preventDefault();
			}).appendTo(base.$actions);
		}
		
		base.setupProgressBar = function(){
			base.progress = {}
			
			base.progress.$filename = $("<div class='filename'>No File Selected</div>").appendTo(base.$frame);
			base.progress.$percent = $("<div class='percent'>0%</div>").appendTo(base.$frame);
			base.progress.$bar = $("<div class='progress bar'></div>").appendTo(base.$frame);
			base.progress.$display = $("<div class='progressbar'>&nbsp;</div>").appendTo(base.progress.$bar);
			
			base.$el.find("input:file:first").change(function(e){
				filename = this.value.split("\\");
				base.progress.$filename.text(filename[filename.length-1]);
				base.progress.$percent.text("0%");
			})
			
			base.$el.bind("upload-progress", function(e,json){
				base.progress.$display.css({width: json.percent + "%"});
				base.progress.$percent.text(json.percent + "%");
			}).bind("upload-complete", function(e, json){
				base.progress.$display.css({width: json.percent + "%"});
				base.progress.$percent.text("Finishing...");
			}).bind("upload-started", function(e){
				base.progress.$display.css({width:"0%"});
				base.progress.$percent.text("Starting...");
			}).bind("upload-error", function(e, json){
				base.progress.$percent.text("Upload Error!");	
				base.prepareForm();
				alert("The file you attempted to upload was too large. \n Files can be JPEG, PNG, or GIF files, and must be under 3MB in size.");
				base.$actions.fadeIn("slow");
				base.$frame.animate({height:195}, "fast");
				base.$shadow.animate({height:215}, "fast");
				base.progress.$display.css({width: 0 + "%"});
			});
		}
		
		base.prepareForm = function(){
			base.generateUuid();
			
			if(base.action == null){
				base.action = base.$el.attr("action");
			}
			
			var progressBarId = "progressBar-" + base.getUuid();
			
			base.setupIFrame();

			base.$el.attr("action", base.action
				+ "?X-Progress-ID=" + base.getUuid()).attr("target", progressBarId);
				
			return base.$el;
		}
		
		base.setupIFrame = function(){
			var progressBarId = "progressBar-" + base.getUuid();
			
			if(base.$iframe) base.$iframe.remove();
			
			base.$iframe = $("<iframe name='" + progressBarId 
				+ "' style='height:0;width:0;position:absolute'></iframe>").appendTo(document.body);
		}
		
		base.getUuid = function(){
			if(base.uuid == null){
				base.generateUuid();
			}
			return base.uuid;
		}
		
		base.generateUuid = function(){
			base.uuid = "";
			for (i = 0; i < 32; i++) { base.uuid += Math.floor(Math.random() * 16).toString(16); }
		}
		
		base.beginUpload = function(){
			if(base.validateFiles()){
				base.$el.trigger("upload-started");
				
				base.$actions.fadeOut("fast");
				base.$frame.animate({height:140}, "slow");
				base.$shadow.animate({height:160}, "slow");
				
				if(base.timer) window.clearInterval(base.timer);

				base.timer = window.setInterval(function(){
					base.checkUploadProgress();
				}, base.options.interval);

				base.$el.submit();
			} else {
				alert("You must select an image file to upload");
			}
		}
		
		base.validateFiles = function(){
			var one_file_setup = false;
			
			base.$el.find("input:file").each(function(){
				if($(this).val() != "") one_file_setup = true;
			});
			
			return one_file_setup;
		}
		
		this.checkUploadProgress = function(){
			// Don't sent multiple requests
			if(base.xhr){
				if(base.xhr.status != 200)
					return;
			}
			
			base.xhr = $.ajax({
				beforeSend: function(xhr){
					xhr.setRequestHeader("X-Progress-ID", base.getUuid());
				},
				success: function(json){
					json = eval(json.replace(/^([^(]?\()/g,'('));
					if(json.state == "uploading"){
						json.percent = Math.floor((json.received / json.size) * 100);
						base.$el.trigger('upload-progress', json);
					} else if (json.state == "done"){
						window.clearInterval(base.timer);
						json.percent = 100;
						base.$el.trigger('upload-complete', json);
					} else if (json.state == "error") {
						if(json.status == 413 || json.status == 500){
							window.clearInterval(base.timer);
							base.$el.trigger('upload-error', json);
						} else {
							
						}
					}
				},
				error: function(xhr, textStatus, errorThrown){
					window.clearInterval(base.timer);
					base.$el.trigger("upload-error", xhr);
				},
				cache: false,
				url: "/progress"
			});
			
		}

		base.show = function(){
			scroll(0,0);
			base.$overlay.css({opacity: 0}).show().animate({opacity:0.7},"fast");
			base.$shadow.css({opacity: 0}).show().animate({opacity:0.5},"fast");
			base.$frame.fadeIn("fast");
			return base.$el
		}
		
		base.hide = function(){
			base.$overlay.fadeOut("fast");
			base.$shadow.fadeOut("fast");
			base.$frame.fadeOut("fast");
			return base.$el
		}
        
        base.init();
    }

	
    $.UploadDialog.defaultOptions = {
        type: "image",
        path: "",
		title: "Upload Photo",
		actionLabel: "Begin Upload",
		cancelLabel: "Cancel",
		interval: 2000
    }
	

    $.fn.uploadDialog = function(options){
		if(options == "show"){
			return this.getUploadDialog().show();
		} else if (options == "hide"){
			return this.getUploadDialog().hide();			
		} else {
		    return this.each(function(){
	            (new $.UploadDialog(this, options));				
	        });
		}
    }


	
    // This function breaks the chain, but returns
    // the UploadDialog if it has been attached to the object.
    $.fn.getUploadDialog = function(){
        return this.data("UploadDialog");
    }
	
})(jQuery);