(function($) {
	$.ymkShowOnTop = {
		defaults : {
			setup: {
				// method to be used for inserting the ymkShowOnTop into the DOM.
				// Permitted values are 'appendTo', 'prependTo', 'insertBefore', and 'insertAfter'
				insertionType: 'insertAfter',
				// element in the DOM the plugin will reference when inserting the clueTip.
				insertionElement: '#content_placeholder'
			},
		
			ymkShowOnTopzIndex : 97,	// Sets the z-index style property of the ymkShowOnTop
			local : true, 				// Whether to use content from the same page for the ymkShowOnTop's body
			localPrefix : null, 		// string to be prepended to the tip attribute if local is true
			localIdSuffix : null,	 	// string to be appended to the ymkShowOnTop content element's id if local is true
			hideLocal : true, 			// If local option is set to true, this determines whether local content
										// to be shown in ymkShowOnTop should be hidden at its original location
			attribute : 'data-in', 		// the attribute to be used for fetching the ymkShowOnTop's body content
			ymkShowOnTopClass: 'default',	// class added to outermost clueTip div in the form of 'cluetip-' + clueTipClass.
			waitImage : true,			// whether to show a "loading" img, which is set in jquery.ymkShowOnTop.css
			cursor : 'help',
			arrows : false,				// if true, displays arrow on appropriate side of ymkShowOnTop
			sticky : true,				// keep visible until manually closed
			mouseOutClose : false,		// close when ymkShowOnTop is moused out
			activation : 'hover',		// set to 'click' to force user to click to show ymkShowOnTop
										// set to 'focus' to show on focus of a form element and hide on blur
			clickThrough : true,		// if true, and activation is not 'click', then clicking on link will take user to the link's href,
										// even if href and tipAttribute are equal
			delayedClose : 0, 			// close ymkShowOnTop on a timed delay (experimental)
			closePosition : 'top', 		// location of close text for sticky ymkShowOnTops; can be 'top' or 'bottom' or 'title'
			closeText : 'Close', 		// text (or HTML) to to be clicked to close sticky ymkShowOnTops
			truncate : 0, 				// number of characters to truncate ymkShowOnTop's contents. if 0, no truncation occurs

			// effect and speed for opening ymkShowOnTops
			fx : {
				open : 'show', // can be 'show' or 'slideDown' or 'fadeIn'
				openSpeed : ''
			},

			// settings for when hoverIntent plugin is used
			hoverIntent : {
				sensitivity : 3,
				interval : 50,
				timeout : 0
			},

			// short-circuit function to run just before ymkShowOnTop is shown.
			onActivate : function(e) {return true;},
			// function to run just after ymkShowOnTop is shown.
			onShow : function(ct, ci) {},
			// function to run just after ymkShowOnTop is hidden.
			onHide : function(ct, ci) {},
			// whether to cache results of ajax request to avoid unnecessary hits to server
			ajaxCache : true,

			// process data retrieved via xhr before it's displayed
			ajaxProcess : function(data) {
				data = data.replace(/<(script|style|title)[^<]+<\/(script|style|title)>/gm,'').replace(/<(link|meta)[^>]+>/g, '');
				return data;
			},

			// can pass in standard $.ajax() parameters. Callback functions, such as beforeSend,
			// will be queued first within the default callbacks.
			// The only exception is error, which overrides the default
			ajaxSettings : {
				// error: function(ct, ci) { /* override default error callback */ },
				// beforeSend: function(ct, ci) { /* called first within default beforeSend callback */ },
				dataType : 'html'
			},
			debug : false

		}
	};
	var $ymkShowOnTop, $ymkShowOnTopInner, $ymkShowOnTopOuter, $ymkShowOnTopTitle, $ymkShowOnTopArrows, $ymkShowOnTopWait, $dropShadow, imgCount,
		standardClasses = 'ui-widget ui-widget-content ui-ymkShowOnTop',
		$ymkLastHoverClass;


	$.fn.ymkShowOnTop = function(js, options) {
		if (typeof js == 'object') {
			options = js;
			js = null;
		}
		if (js == 'destroy') {
			$(document).unbind('.ymkShowOnTop');
			$('#ymkShowOnTop').remove();
			$.removeData(this, 'title');
			$.removeData(this, 'ymkShowOnTop');
			return this.unbind('.ymkShowOnTop');
		}

		// merge per-call options with defaults
		options = $.extend(true, {}, $.ymkShowOnTop.defaults, options || {});

		/** =create ymkShowOnTop divs * */
		var insertionType = (/appendTo|prependTo|insertBefore|insertAfter/).test(options.setup.insertionType) ? options.setup.insertionType : 'appendTo',
			insertionElement = options.setup.insertionElement || 'body';

		if (!$('#ymkShowOnTop').length) {
			$( ['<div id="ymkShowOnTop">',
				'<div id="ymkShowOnTop-outer" class="ui-ymkShowOnTop-outer">',
				'<div id="ymkShowOnTop-inner" class="ui-ymkShowOnTop-content"></div>',
				'</div>',
				//'<div id="ymkShowOnTop-extra"></div>',
				//'<div id="ymkShowOnTop-arrows" class="ymkShowOnTop-arrows"></div>',
				'</div>' ].join(''))
				[insertionType](insertionElement).hide();

			var ymkShowOnTopzIndex = +options.ymkShowOnTopzIndex;

			$ymkShowOnTopParent = $(insertionElement);
			$ymkShowOnTop = $('#ymkShowOnTop');
			$ymkShowOnTopOuter = $('#ymkShowOnTop-outer').css({zIndex : ymkShowOnTopzIndex});
			$ymkShowOnTopInner = $('#ymkShowOnTop-inner');
			//$ymkShowOnTopTitle = $('#ymkShowOnTop-title');
			//$ymkShowOnTopArrows = $('#ymkShowOnTop-arrows');
			$ymkShowOnTopWait = $('<div id="ymkShowOnTop-waitimage"></div>')
				.insertBefore($ymkShowOnTop).hide();
		}
		var ymkShowOnTopPadding = (parseInt($ymkShowOnTop.css('paddingLeft'), 10) || 0)	+ (parseInt($ymkShowOnTop.css('paddingRight'), 10) || 0);


		this.each(function(index) {
			var link = this,
				$link = $(this),
				// support metadata plugin (v1.0 and 2.0)
				opts = $.extend(true, {}, options, $.metadata ? $link.metadata() : $.meta ? $link.data() : {}),
				// start out with no contents (for ajax activation)
				ymkShowOnTopContents = false,
				isActive = false,
				closeOnDelay = 0,
				tipAttribute = $link.attr(opts.attribute),
				ctClass = opts.ymkShowOnTopClass;

				ymkShowOnTopzIndex = +opts.ymkShowOnTopzIndex;
				$link.data('ymkShowOnTop', {title : link.title,zIndex : ymkShowOnTopzIndex});

				if (!tipAttribute && !opts.splitTitle && !js) {
					return true;
				}
				// if hideLocal is set to true, on DOM ready hide the local content that will be displayed in the ymkShowOnTop
				if (opts.local && opts.localPrefix) {tipAttribute = opts.localPrefix + tipAttribute;}
				if (opts.local && opts.hideLocal && tipAttribute) {$(tipAttribute + ':first').hide();}
				
				// parse the title
				var tipParts;
				var tipTitle = ''; //(opts.attribute != 'title') ? $link.attr(opts.titleAttribute) : '';
				if (opts.splitTitle) {
					if (tipTitle == undefined) {tipTitle = '';}
					tipParts = tipTitle.split(opts.splitTitle);
					tipTitle = tipParts.shift();
				}
				if (opts.escapeTitle) {
					tipTitle = tipTitle.replace(/&/g,'&amp;').replace(/>/g,'&gt;').replace(/</g,'&lt;');
				}
		
				var localContent;
				function returnFalse() {return false;}

				/***************************************
				 * ACTIVATION
				 ****************************************/

				// activate ymkShowOnTop
				var activate = function(event) {
					var continueOn = opts.onActivate($link);
					if (continueOn === false) {
						return false;
					}
					isActive = true;
					if (tipAttribute == $link.attr('href')) {
						$link.css('cursor', opts.cursor);
					}
					if (opts.hoverClass) {
						$link.addClass(opts.hoverClass);
					}
					
					/***************************************
					 * load a string from ymkShowOnTop method's first argument
					 ***************************************/
					if (js) {
						if (typeof js == 'function') {
							js = js.call(link);
						}
						$ymkShowOnTopInner.html(js);
						ymkShowOnTopShow(pY);
					}
					/***************************************
					 * load the title attribute only (or user-selected attribute).
					 * ymkShowOnTop title is the string before the first delimiter
					 * subsequent delimiters place ymkShowOnTop body text on separate lines
					 ***************************************/

					else if (tipParts) {
						var tpl = tipParts.length;
						$ymkShowOnTopInner.html(tpl ? tipParts[0] : '');
						if (tpl > 1) {
							for ( var i = 1; i < tpl; i++) {
								$ymkShowOnTopInner.append('<div class="split-body">' + tipParts[i] + '</div>');
							}
						}
						ymkShowOnTopShow(pY);
					}
					/***************************************
					 * load external file via ajax
					 ***************************************/

					else if (!opts.local && tipAttribute.indexOf('#') !== 0) {
						if (/\.(jpe?g|tiff?|gif|png)(?:\?.*)?$/i.test(tipAttribute)) {
							$ymkShowOnTopInner.html('<img src="' + tipAttribute + '" alt="' + tipTitle + '" />');
							ymkShowOnTopShow(pY);
						} else {
							var optionBeforeSend = opts.ajaxSettings.beforeSend,
							optionError = opts.ajaxSettings.error,
							optionSuccess = opts.ajaxSettings.success,
							optionComplete = opts.ajaxSettings.complete;
							var ajaxSettings = {
								cache : false, // force requested page not to be cached by browser
								url : tipAttribute,
								beforeSend : function(xhr) {
									if (optionBeforeSend) {optionBeforeSend.call(link, xhr,	$ymkShowOnTop, $ymkShowOnTopInner);}
									$ymkShowOnTopOuter.children().empty();
									if (opts.waitImage) {
										$ymkShowOnTopWait
												.css({zIndex: $link.data('ymkShowOnTop').zIndex - 1})
												.show();
									}
								},
								error : function(xhr, textStatus) {
									if (isActive) {
										if (optionError) {
											optionError.call(link, xhr,textStatus, $ymkShowOnTop,$ymkShowOnTopInner);
										} else {
											$ymkShowOnTopInner.html('<i>sorry, the contents could not be loaded</i>');
										}
									}
								},
								success : function(data, textStatus) {
									ymkShowOnTopContents = opts.ajaxProcess.call(link, data);
									if (isActive) {
										if (optionSuccess) {optionSuccess.call(link, data,textStatus, $ymkShowOnTop,$ymkShowOnTopInner);}
										$ymkShowOnTopInner.html(ymkShowOnTopContents);
									}
								},
								complete : function(xhr, textStatus) {
									if (optionComplete) {optionComplete.call(link, xhr,textStatus, $ymkShowOnTop,$ymkShowOnTopInner);}
									var imgs = $ymkShowOnTopInner[0].getElementsByTagName('img');
									imgCount = imgs.length;
									for ( var i = 0, l = imgs.length; i < l; i++) {
										if (imgs[i].complete) {
											imgCount--;
										}
									}
									if (imgCount && !$.browser.opera) {
										$(imgs).bind('load error', function() {
											imgCount--;
											if (imgCount < 1) {
												$ymkShowOnTopWait.hide();
												if (isActive) { ymkShowOnTopShow(pY); }
											}
										});
									} else {
										$ymkShowOnTopWait.hide();
										if (isActive) { ymkShowOnTopShow(pY); }
									}
								}
							};
							var ajaxMergedSettings = $.extend(true, {},opts.ajaxSettings, ajaxSettings);

							$.ajax(ajaxMergedSettings);
						}

						/***************************************
						 * load an element from the same page
						 ***************************************/
					} else if (opts.local) {

						var $localContent = $(tipAttribute + (/#\S+$/.test(tipAttribute) ? '': ':eq(' + index + ')')).clone(true).removeClass('tag_info_src').show();
						if (opts.localIdSuffix) {
							$localContent.attr('id', $localContent[0].id + opts.localIdSuffix);
						}
						$ymkShowOnTopInner.html($localContent);
						ymkShowOnTopShow(0);
					}
				};

				// get dimensions and options for ymkShowOnTop and prepare it to be shown
				var ymkShowOnTopShow = function(bpY) {
					$ymkShowOnTop.addClass('ymkShowOnTop-' + ctClass);
					if (opts.truncate) {
						var $truncloaded = $ymkShowOnTopInner.text().slice(0,opts.truncate) + '...';
						$ymkShowOnTopInner.html($truncloaded);
					}

					function doNothing() {}; // empty function

					if (opts.sticky) {
						var $closeLink = $('<div id="ymkShowOnTop-close"><a href="#">' + opts.closeText + '</a></div>');
						(opts.closePosition == 'bottom') ? $closeLink.appendTo($ymkShowOnTopInner): (opts.closePosition == 'title') ? $closeLink.prependTo($ymkShowOnTopTitle) : $closeLink.prependTo($ymkShowOnTopInner);
						$closeLink.bind('click.ymkShowOnTop', function() {
							ymkShowOnTopClose();
							return false;
						});
						if (opts.mouseOutClose) {
							$ymkShowOnTop.bind('mouseleave.ymkShowOnTop', function() {
								ymkShowOnTopClose();
							});
						} else {
							$ymkShowOnTop.unbind('mouseleave.ymkShowOnTop');
						}
					}
					// now that content is loaded, finish the positioning
					var direction = '';
					$ymkShowOnTopOuter.css( {zIndex : $link.data('ymkShowOnTop').zIndex});
					// add classes
					var dynamicClasses = ' clue-' + ctClass + ' ymkShowOnTop-' + ctClass;
					$ymkShowOnTop.attr( {'className' : standardClasses + dynamicClasses});
					// set up arrow positioning to align with element
//					if (opts.arrows) {
//						var bgY = (posY - tipY - opts.dropShadowSteps);
//						$ymkShowOnTopArrows.css({top : (/(left|right)/.test(direction) && posX >= 0 && bgY > 0) ? bgY + 'px': /(left|right)/.test(direction) ? 0: ''}).show();
//					} else {
//						$ymkShowOnTopArrows.hide();
//					}

					// (first hide, then) ***SHOW THE ymkShowOnTop***
					// handle dropshadow divs first
//					$dropShadow = createDropShadows(opts);
//					if ($dropShadow && $dropShadow.length) {
//						$dropShadow.hide().css( {height : tipHeight,width : tipInnerWidth,zIndex : $link.data('ymkShowOnTop').zIndex - 1}).show();
//					}
					$ymkShowOnTopParent.hide();
					$ymkShowOnTop.hide()[opts.fx.open](opts.fx.openSpeed || 0);
//					if ($.fn.bgiframe) {$ymkShowOnTop.bgiframe();}
					// delayed close (not fully tested)
					if (opts.delayedClose > 0) {
						closeOnDelay = setTimeout(ymkShowOnTopClose,opts.delayedClose);
					}
					// trigger the optional onShow function
					opts.onShow.call(link, $ymkShowOnTop, $ymkShowOnTopInner);
					$('.' + $ymkLastHoverClass).removeClass($ymkLastHoverClass);
					if ($link.attr('data-hover-style')) {
						$ymkLastHoverClass = $link.attr('data-hover-style');
						$link.addClass($ymkLastHoverClass);
					} else if ($link.attr('data-hover-on')){
						$ymkLastHoverClass = $($link.attr('data-hover-on')).attr('data-hover-style');
						$($link.attr('data-hover-on')).addClass($ymkLastHoverClass);
					}
				};

				/***************************************
				   =INACTIVATION
				***************************************/
				var inactivate = function(event) {
					isActive = false;
					$ymkShowOnTopWait.hide();
					if (!opts.sticky || (/click|toggle/).test(opts.activation)) {
						ymkShowOnTopClose();
						clearTimeout(closeOnDelay);
					}
					if (opts.hoverClass) {
						$link.removeClass(opts.hoverClass);
					}
				};
				// close ymkShowOnTop and reset some things
				var ymkShowOnTopClose = function() {
					$ymkShowOnTopOuter.parent().hide().removeClass();
					$ymkShowOnTopParent.hide()[opts.fx.open](opts.fx.openSpeed || 0);
					opts.onHide.call(link, $ymkShowOnTop, $ymkShowOnTopInner);
					$link.removeClass('ymkShowOnTop-clicked');
					if (tipTitle) {
						$link.attr(opts.titleAttribute, tipTitle);
					}
					$link.css('cursor', '');
					if (opts.arrows) {
						$ymkShowOnTopArrows.css( {top : ''});
					}
					$('.' + $ymkLastHoverClass).removeClass($ymkLastHoverClass);
				};

				$(document).bind('hideymkShowOnTop', function(e) {
					ymkShowOnTopClose();
				});
				/***************************************
				   =BIND EVENTS
				 ***************************************/
				// activate by click
				if ((/click|toggle/).test(opts.activation)) {
					$link.bind('click.ymkShowOnTop', function(event) {
						if ($ymkShowOnTop.is(':hidden')	|| !$link.is('.ymkShowOnTop-clicked')) {
							activate(event);
							$('.ymkShowOnTop-clicked').removeClass('ymkShowOnTop-clicked');
							$link.addClass('ymkShowOnTop-clicked');
						} else {
							inactivate(event);
						}
						return false;
					});
					// activate by focus; inactivate by blur
				} else if (opts.activation == 'focus') {
					$link.bind('focus.ymkShowOnTop', function(event) {
						$link.attr('title', '');
						activate(event);
					});
					$link.bind('blur.ymkShowOnTop', function(event) {
						$link.attr('title', $link.data('thisInfo').title);
						inactivate(event);
					});
					// activate by hover
				} else {
					// clicking is returned false if clickThrough option is set to false
					$link[opts.clickThrough ? 'unbind' : 'bind']('click.ymkShowOnTop', returnFalse);
					// set up mouse tracking
					var mouseTracks = function(evt) {
						if (opts.tracking == true) {
							var trackX = posX - evt.pageX;
							var trackY = tipY ? tipY - evt.pageY : posY - evt.pageY;
							$link.bind('mousemove.ymkShowOnTop', function(evt) {
								$ymkShowOnTop.css( {left : evt.pageX + trackX,top : evt.pageY + trackY});
							});
						}
					};
					if ($.fn.hoverIntent && opts.hoverIntent) {
						$link.hoverIntent( {
							sensitivity : opts.hoverIntent.sensitivity,
							interval : opts.hoverIntent.interval,
							over : function(event) {
								activate(event);
								mouseTracks(event);
							},
							timeout : opts.hoverIntent.timeout,
							out : function(event) {inactivate(event);$link.unbind('mousemove.ymkShowOnTop');}
						});
					} else {
						$link.bind('mouseenter.ymkShowOnTop', function(event) {
							activate(event);
							mouseTracks(event);
						})
						.bind('mouseleave.ymkShowOnTop', function(event) {
							inactivate(event);
							$link.unbind('mousemove.ymkShowOnTop');
						});
					}

					$link.bind('mouseover.ymkShowOnTop', function(event) {
						$link.attr('title', '');
					}).bind('mouseleave.ymkShowOnTop', function(event) {
						$link.attr('title', $link.data('ymkShowOnTop').title);
					});
				}
			});
		return this;
	};

	$.fn.ymkShowOnTop.defaults = $.ymkShowOnTop.defaults;

	/*$.fn.showOnTop = function(ebase) {
		//get the position of the placeholder element  
		var pos = $(ebase).offset();
		var eWidth = $(ebase).outerWidth();
		var mWidth = $this.outerWidth();
		var left = (pos.left + eWidth - mWidth) + "px";
		var top = 3 + pos.top + "px";
		//show the menu directly over the placeholder  
		$this.css( {
			position : 'absolute',
			zIndex : 5000,
			left : left,
			top : top
		});

		$this.hide().fadeIn();
	};*/
})(jQuery);
