/**
 * Ajax upload
 * Project page - http://valums.com/ajax-upload/
 * Copyright (c) 2008 Andris Valums, http://valums.com
 * Licensed under the MIT license (http://valums.com/mit-license/)
 * Version 2.0 (21.02.2009)
 */

(function(){
	
var d = document, w = window;

/**
 * Get element by id
 */	
function $(element){
	if (typeof element == "string")
		element = d.getElementById(element);
	return element;
}

/**
 * Attaches event to a dom element
 */
function addEvent(el, type, fn){
	if (w.addEventListener){
		el.addEventListener(type, fn, false);
	} else if (w.attachEvent){
		var f = function(){
		  fn.call(el, w.event);
		};			
		el.attachEvent('on' + type, f)
	}
}


/**
 * Creates and returns element from html chunk
 */
var toElement = function(){
	var div = d.createElement('div');
	return function(html){
		div.innerHTML = html;
		var el = div.childNodes[0];
		div.removeChild(el);
		return el;
	}
}();

function hasClass(ele,cls){
	return ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)'));
}
function addClass(ele,cls) {
	if (!hasClass(ele,cls)) ele.className += " "+cls;
}
function removeClass(ele,cls) {
	var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)');
	ele.className=ele.className.replace(reg,' ');
}

function getOffset(el){
	if (w.jQuery){
		return jQuery(el).offset();
	}
			
	var top = 0, left = 0;
	do {
		top += el.offsetTop  || 0;
		left += el.offsetLeft || 0;
	} while (el = el.offsetParent);
					
	return {
		left : left,
		top : top
	};
}

function getBox(el){
	var left, right, top, bottom;	
	var offset = getOffset(el);
	left = offset.left;
	top = offset.top;
	right = left + el.offsetWidth;
	bottom = top + el.offsetHeight;		
			
	return {
		left: left,
		right: right,
		top: top,
		bottom: bottom
	};
}

/**
 * Crossbrowser mouse coordinates
 */
function getMouseCoords(e){		
	// pageX/Y is not supported in IE
	// http://www.quirksmode.org/dom/w3c_cssom.html			
	if (!e.pageX && e.clientX){
		return {
			x: e.clientX + d.body.scrollLeft + d.documentElement.scrollLeft,
			y: e.clientY + d.body.scrollTop + d.documentElement.scrollTop
		};
	}
	
	return {
		x: e.pageX,
		y: e.pageY
	};		

}
/**
 * Function generates unique id
 */		
var getUID = function(){
	var id = 0;
	return function(){
		return 'ValumsAjaxUpload' + id++;
	}
}();

function fileFromPath(file){
	return file.replace(/.*(\/|\\)/, "");			
}

function getExt(file){
	return (/[.]/.exec(file)) ? /[^.]+$/.exec(file.toLowerCase()) : '';
}	
		
(function(){
	// iframe will be shared by each instance.
	var iframe = null;
		
	// Please use AjaxUpload , Ajax_upload will be removed in the next version
	Ajax_upload = AjaxUpload = function(button, options){
		if (button.jquery){
			// jquery object was passed
			button = button[0];
		} else if (typeof button == "string" && /^#.*/.test(button)){					
			button = button.slice(1);				
		}
		button = $(button);	
		
		this._input = null;
		this._button = button;
		this._disabled = false;
		this._submitting = false;
				
		this._settings = {
			// Location of the server-side upload script
			action: 'upload.php',			
			// File upload name
			name: 'userfile',
			// Additional data to send
			data: {},
			// Submit file as soon as it's selected
			autoSubmit: true,
			// When user selects a file, useful with autoSubmit disabled			
			onChange: function(file, extension){},					
			// Callback to fire before file is uploaded
			// You can return false to cancel upload
			onSubmit: function(file, extension){},
			// Fired when file upload is completed
			onComplete: function(file, response) {}
		};

		// Merge the users options with our defaults
		for (var i in options) {
			this._settings[i] = options[i];
		}
		
		this._createInput();
		this._rerouteClicks();
		
		// 1 iframe for all inputs
		if (!iframe) {
			this._createIframe();
		}
	}
		
	// assigning methods to our class
	AjaxUpload.prototype = {
		setData : function(data){
			this._settings.data = data;
		},
		disable : function(){
			this._disabled = true;
		},
		enable : function(){
			this._disabled = false;
		},
		// use setData instead, set_data will be removed in the next version
		set_data : function(data){
			this.setData(data);
		},		
		/**
		 * Creates invisible file input above the button 
		 */
		_createInput : function(){
			var self = this;
			
			var input = d.createElement("input");
			input.setAttribute('type', 'file');
			input.setAttribute('name', this._settings.name);
			var styles = {
				'position' : 'absolute'
				,'margin': '-5px 0 0 -175px'
				,'padding': 0
				,'width': '220px'
				,'height': '10px'								
				,'opacity': 0
				,'cursor': 'pointer'
				,'display' : 'none'								
			};
			for (var i in styles){
				input.style[i] = styles[i];
			}
			
			// Make sure that element opacity exists
			// (IE uses filter instead)
			if ( ! (input.style.opacity === "0")){
				input.style.filter = "alpha(opacity=0)";
			}					
			d.body.appendChild(input);	
			
			addEvent(input, 'change', function(){
				// get filename from input
				var file = fileFromPath(this.value);	
				if(self._settings.onChange.call(self, file, getExt(file)) == false ){
					return;				
				}														
				// Submit form when value is changed
				if (self._settings.autoSubmit){
					self.submit();						
				}						
			});
			
			this._input = input;
		},
		_rerouteClicks : function (){
			var self = this;
		
			// IE displays 'access denied' error when using this method
			// other browsers just ignore click()
			// addEvent(this._button, 'click', function(e){
			//   self._input.click();
			// });				

			var box, over = false;			
			addEvent(self._button, 'mouseover', function(e){
				if (!self._input || over) return;
				over = true;
				box = getBox(self._button);								
			});
			
			// we can't use mouseout on the button,
			// because invisible input is over it
			addEvent(document, 'mousemove', function(e){
				var input = self._input;
				if (!input || !over) return;
				if (self._disabled){
					removeClass(self._button, 'hover');
					input.style.display = 'none';
					return;
				}	
											
				var c = getMouseCoords(e);
						
				if ((c.x >= box.left) && (c.x <= box.right) && 
				(c.y >= box.top) && (c.y <= box.bottom)){
				
					input.style.top = c.y + 'px';
					input.style.left = c.x + 'px';
					input.style.display = 'block';
					addClass(self._button, 'hover');				
				} else {		
					// mouse left the button
					over = false;
					input.style.display = 'none';
					removeClass(self._button, 'hover');
				}			
			});			
				
		},
		/**
		 * Creates iframe with unique name
		 */
		_createIframe : function(){
			// unique name
			// We cannot use getTime, because it sometimes return
			// same value in safari :(
			var id = getUID();
			// I haven't forgotten var statement, 1 iframe will be shared by each instance.
			_iframe = toElement('<iframe name="' + id + '" />');
			_iframe.id = id;
			_iframe.style.display = 'none';
			d.body.appendChild(_iframe);				
		},
		/**
		 * Upload file without refreshing the page
		 */
		submit : function(){
			var self = this, settings = this._settings;	
						
			if (this._input.value === ''){
				// there is no file
				return;
			}
											
			// get filename from input
			var file = fileFromPath(this._input.value);			

			// execute user event
			if (! (settings.onSubmit.call(this, file, getExt(file)) == false)) {
				// Do not submit if user function returns false										
				var form = this._createForm();
				form.appendChild(this._input);

				form.submit();
				d.body.removeChild(form);				
				form = null;
				this._input = null;
				
				// create new input
				this._createInput();
				
				var iframe = _iframe;				
				addEvent(iframe, 'load', function(){
					var toDeleteFlag = false;
		
					if (iframe.src == "about:blank"){						
						// First time around, do not delete.
						if( toDeleteFlag ){
							iframe.remove();
						}
 						return;
					}					
					
					var doc = iframe.contentDocument ? iframe.contentDocument : frames[iframe.id].document;
					var response = doc.body.innerHTML;
										
					settings.onComplete.call(self, file, response);
					
					// Reload blank page, so that reloading main page
					// does not re-submit the post. Also, remember to
					// delete the frame
					iframe.src = "about:blank";
					toDeleteFlag = true;					
				});
				
				// Create new iframe, so we can have multiple uploads at once
				this._createIframe();
				
			} else {
				// clear input to allow user to select same file
				this._input.value = '';						
			}
		},		
		/**
		 * Creates form, that will be submitted to iframe
		 */
		_createForm : function(){
			var settings = this._settings;
			
			// method, enctype must be specified here
			// because changing this attr on the fly is not allowed in IE 6/7
			// $('<form method="post" enctype="multipart/form-data"></form>')			
			var form = toElement('<form method="post" enctype="multipart/form-data"></form>');
			form.style.display = 'none';
			form.action = settings.action;
			form.target = _iframe.name;
			d.body.appendChild(form);
			
			// Create hidden input element for each data key
			for (var prop in settings.data){
				var el = d.createElement("input");
				el.type = 'hidden';
				el.name = prop;
				el.value = settings.data[prop];
				form.appendChild(el);
			}			
			return form;
		}	
	};
})();


})();
