(function($) {
	$.fn.mutationObserver = function(action, callbackFn) {
		var result = this;

		this.each(function(i, element) {
			var $element = $(element);
			var instance = $element.data('plugin_mutationObserver');

			if (action === 'destroy' && instance) {
				instance.observer.disconnect();
				instance.observer = null;
				$element.removeData('plugin_mutationObserver');
				return;
			}

			if (!instance) {
				var observer = new MutationObserver(function(mutations) {
					mutations.forEach(function(mutation) {
						instance.callbacks.forEach(function(callbackFn) {
							callbackFn(mutation);
						});
					});
				});

				observer.observe(element, {
					attributes: true,
					childList: true,
					characterData: true
				});

				instance = {
					observer: observer,
					callbacks: []
				};
				$element.data('plugin_mutationObserver', instance);
			}

			if (typeof action === 'function') {
				instance.callbacks.push(action);
			} else if (action === 'callbacks') {
				if (callbackFn && callbackFn.length >= 0) {
					// used as a setter
					instance.callbacks = callbackFn;
				} else {
					// used as a getter for the first element
					result = instance.callbacks;
					return false;// break the $.fn.each() iteration
				}
			}
		});

		return result;
	};
})(jQuery);
