(function($) {
	var timeoutId = false;
	var completeIterations = 0;
	var ogText = '';
	var that;
	var isBound = false;
	
	var config = {	eventIterations : 10, 
					eventDelay : 400,		// in ms
					startDelay : 100		// in ms
				};
	
	$.fn.paste = function(fn,settings) {
		if (settings) {
			$.extend(config,settings);
		}
		
		supported = eventSupported('onpaste');
		
		if (supported) {
			return fn ? this.bind('paste',fn) : this.trigger('paste');
		} else {
			if (isBound === false) {
				this.bind('paste',fn);
			}
			that = this;
			this.mousedown(function(event) {
				if (detectClick(event)) {
					if (isRightClick(event)) {
						runEventLoop($(this));
					}
				} else { // else fire on any click
					runEventLoop($(this));
				}
			});
			
			if (eventSupported('onkeydown')) {
				this.keydown(function(event) {
					checkKeyboardPaste(event);
				});
			} else {
				this.keyup(function(event) {
					checkKeyboardPaste(event);
				});
			}
		}
		
		return this;
	};
	
	function eventSupported(testEvent) {
		testEl = document.createElement('input');
		supported = (testEvent in testEl);
		if (!supported) {
			testEl.setAttribute(testEvent, 'return;');
			supported = typeof testEl[testEvent] === 'function';
		}
		
		return supported;
	}
	
	function detectClick(event) {
		if (typeof event.button !== 'undefined') {
			return true;
		} else if (typeof event.which !== 'undefined') {
			return true;
		} else {
			return false;
		}
	}
	
	function checkKeyboardPaste(event) {
		// metaKey is normalized by jQuery to mean command on macs and ctrl for pcs
		if (event.metaKey && (event.which === 86 || event.which === 118)) {
			//no check needed, we know this is a paste
			that.trigger('paste');
		}
	}
	
	function isRightClick(event) {
		if (detectClick(event)) {
			return (typeof event.button !== 'undefined') ? (event.button === 2) : (event.which === 3);
		} else {
			return false;
		}
	}
	
	function checkPaste(input) {
		if (completeIterations++ < config.eventIterations) {
			if (input.val() !== ogText) {
				that.trigger('paste');
				cancelEventLoop();
			}
		} else {
			cancelEventLoop();
		}
	}
	
	function runEventLoop(input) {
		if (config.startDelay > 0) {
			setTimeout(function() {
				ogText = input.val();
				timeoutId = setInterval(checkPaste,config.eventDelay,input);
			},config.startDelay);
		} else {
			ogText = input.val();
			timeoutId = setInterval(checkPaste,config.eventDelay,input);
		}
		
	}
	
	function cancelEventLoop() {
		if (typeof timeoutId !== 'boolean') {
			clearInterval(timeoutId);
			timeoutId = false;
		}
		completeIterations = 0;
	}
})(jQuery);
