// Copyright (c) 2008 Andris Valums, http://valums.com
// Licensed under the MIT license (http://valums.com/MIT-LICENSE.txt)
(function($){
	// we need jQuery to run
	if ( ! $) return;
	
	$.fn.jsupload = function(options){
		var el = this;
		if (el.size() != 1 ){
			alert('Pass only 1 element to jsupload at once');
		}

		new Jsupload(el, options);
	}
	
	/**
	 * @class Creates ajax file upload button
	 * @param el Element that will be converted to upload button
	 * @param User options
	 */
	var Jsupload = function(el, options){
		this.el = el;
		this.form = null;
		this.input = null;
		this.iframe = null;
		
		this.settings = {
			// Location of the serverside upload script
			action: '',			
			// File upload name
			name: 'userfile',
			//Additional parameters to send
			params: {},
			// Function that gets called when file upload is starting
			onSubmit: function() {},
			// Function that gets called when file upload is completed
			onComplete: function() {}
		};

		// Merge the users options with our defaults
		// And then shorten name		
		var settings = $.extend(this.settings, options);		
		
		var parent_form = el.parents('form');		
		// If we have a parent form && action not set
		// Use form's action
		if (parent_form.size() && ! options.action){
			settings.action = parent_form.attr('action');		
		}
		
		if (el.is("input[type='file']")){			
			// el is file input
			this.input = el;
			
			// if name not set use input field's name
			if ( ! options.name){
				settings.name = el.attr('name');
			}
			
		} else { this.create_input(el);	}

		this.create_iframe();
		
		var self = this;		
		this.input.change(function(){
			self.submit();
		});
	}
	// assigning methods to our class
	Jsupload.prototype = {
		/**
		 * Creates form, will contain upload 
		 * button, hidden input elements	
		 */
		create_form : function(){
			// enctype must be specified here
			// because changing this attr on the fly is not allowed
			this.form = 
				$('<form method="post" enctype="multipart/form-data"></form>')
				.appendTo('body')
				.attr({
					"action" : this.settings.action,
					"target" : this.iframe.attr('name')						
				});			

			// Create hidden input element for each param
			for (var i in this.settings.params){	
				$('<input type="hidden" />')
					.appendTo(this.form)
					.attr({
						'name': i,
						'value': this.settings.params[i]
					});
			}
		},
		/**
		 * Creates invisible file input above the el 
		 * @param el
		 */
		create_input : function(el){

			el.wrap('<div></div>');
			var wrapper = el.parent();
			
			wrapper.css({
				position: 'relative',
				overflow: 'hidden',
				
				height: el.height(),
				width: el.width()
			});
			
			if (jQuery.browser.msie){
				// Fixing ie transparent background bug
				el.add(el.parents()).each(function(){
					
					var color = $(this).css('backgroundColor');
					var image = $(this).css('backgroundImage');

					if ( color != 'transparent' ||  image != 'none'){
						$(this).css('opacity', 1);
						return false;
					}
				});				
			}
						
			this.input = 
				$('<input type="file" />')
				.attr('name', this.settings.name)				
				.css({
					'position' : 'absolute',
					'margin': 0,
					'padding': 0,
					'width': '220px',
					'heigth': '10px',
										
					'opacity': 0					
				})
				.appendTo(wrapper);
			
			var self = this;
			// Move the input with the mouse, so the user can't misclick it
			wrapper.mousemove(function(e){
				self.input.css({
					top: e.pageY-wrapper.offset().top-5+'px',
					left: e.pageX-wrapper.offset().left-170+'px'
				});
			});								
		},
		/**
		 * Creates iframe with unique name
		 */
		create_iframe : function(){
			// unique name
			var name = 'iframe_' + new Date().getTime().toString().slice(7);
			// create iframe, so we dont need to refresh page
			this.iframe = 
				$('<iframe name="' + name + '"></iframe>')
				.appendTo('body')
				.css('display', 'none');					
		},
		clone_input : function(){
			var input = this.input, clone, saved_id;

			clone = $('<input type="file" />').insertAfter(input);
			clone.attr('name', this.settings.name);	
			
			// do not copy id - move it
			saved_id = input.attr('id');
			input.attr('id', '');			
			clone.attr('id', saved_id);
			
			// copy other attributes
			clone.attr('class', input.attr('class'));
			clone.attr('style', input.attr('style'));
					
			return clone;		
		},
		submit : function(){			
			var self = this, input = this.input, settings = this.settings, iframe = this.iframe;
			
			// execute user event
			if (settings.onSubmit(input.val()) === false){
				// Do not continue if user func returns false
				return;
			}			
						
			this.create_form();
			
			// clone without a value
			var clone = this.clone_input();

			input.appendTo(this.form);
			this.form.submit();

			// clear
			input.remove();	this.form.remove(); this.form = null;
			
			
			input = this.input = clone;
			
			// bind event
			input.change(function(){
				self.submit();
			});			
			
			iframe.load(function(){
				var result = iframe.contents().find('body').html();
				settings.onComplete(result);
				
				// clear (wait a bit because of FF2 bug)
				setTimeout(function(){
					iframe.remove();
				}, 1);
				
				
			});
			
			// Create new iframe, so we can have multiple uploads at once
			this.create_iframe();		
		}
	};
})(jQuery);