/* global define:false, require:false */
define([
	'jquery',
	'link'
], function($) {
	"use strict";
	// Don't include this in the top-level define block so the build doesn't break.
	require(['link!../../static/projects/finch/css/tooltip'],function(){});
	$.tooltip = $.fn.tooltip = function tooltip(opts) {
		if (this.jquery) {
			var tooltips = $([]);
			this.each(function(i,e){tooltips.push(tooltip($.extend({}, opts, {"anchor": e}))[0]);});
			return tooltips;
		}
		opts = $.extend({}, {
			"content": " ",
			"style": "info",
			"position": "southeast",
			"offset": [5, 5],
			"anchor": "cursor"
		}, opts);
		if (typeof opts.anchor === "string" && opts.anchor !== "cursor") {
			return $(opts.anchor).tooltip(opts);
		}
		// if anchor is a DOM Element
		if (opts.anchor.nodeType) {
			opts.anchor = $(opts.anchor);
		}
		var $tt = $("
").addClass("w-tooltip").html(opts.content).appendTo($("body"));
		var $tooltipPoint = $("  
");
		if (opts.style) {
			$tt.addClass("w-tooltip-" + opts.style);
		}
		if (opts.hideicon) {
			$tt.addClass("w-tooltip-noicon");
		}
		if (opts.anchor === "cursor") {
			$tt.css({"position": "fixed"});
			$("body").bind("mousemove", function(e) {
				if (!$tt.hasClass("active")) {
					return;
				}
				// First, check if we should change position.
				var tooltipRightEdge = parseInt(e.clientX + $tt.width(), 10);
				// If this tooltip will go off the right of the screen, change its direction.
				// Give a decent buffer amount based on the width of the tooltip so it isn't
				// right up against the egde of the screen.
				var current_position = opts.position;
				if (tooltipRightEdge > ($("body").width() / 2) + $tt.width()) {
					current_position = "southwest";
				}
				if (e.clientY > $("body").height() - $tt.width()*0.75) {
					current_position = current_position.replace("south", "north");
				}
				if (current_position.match(/(top|north)/i)) {
					$tt.css({
						bottom: ($(window).height() - e.clientY + opts.offset[1]) + "px",
						top: ""
					});
				}
				else {
					$tt.css({
						top: (e.clientY + opts.offset[1]) + "px",
						bottom: ""
					});
				}
				if (current_position.match(/(left|west)/i)) {
					$tt.css({
						right: ($(window).width() - e.clientX + opts.offset[0]) + "px",
						left: ""
					});
				}
				else {
					$tt.css({
						left: (e.clientX + opts.offset[0]) + "px",
						right: ""
					});
				}
			});
		}
		else if (opts.showTip) {
			$tt.append($tooltipPoint);
			opts.tipOffset = opts.tipOffset || [0, 0];
		}
		$tt.reposition = function reposition() {
			var newPosition = 0;
			var oldPosition = 0;
			if (opts.anchor === "cursor") {
				// nothing to do
				return;
			} else if (opts.anchor && opts.anchor.constructor === Array) {
				$tt.css({"position": "absolute"});
				if (opts.position.match(/(top|north)/i)) {
					$tt.css("bottom", ($("body").height() - opts.anchor[1] + opts.offset[1]) + "px");
				} else {
					$tt.css("top", (opts.anchor[1] + opts.offset[1]) + "px");
				}
				if (opts.position.match(/(left|west)/i)) {
					$tt.css("right", ($("body").width() - opts.anchor[0] + opts.offset[0]) + "px");
				} else {
					$tt.css("left", (opts.anchor[0] + opts.offset[0]) + "px");
				}
				if (opts.showTip) {
					repositionTip(0, opts);
				}
			} else if (opts.anchor && opts.anchor.jquery) {
				$tt.css({"position": "absolute"});
				var anchorPosition = opts.anchor.offset();
				if (opts.position.match(/(top|north)/i)) {
					$tt.css("bottom", ($("body").height() - anchorPosition.top + opts.anchor.outerHeight() + opts.offset[1]) + "px");
				}
				else {
					$tt.css("top", (anchorPosition.top + opts.anchor.outerHeight() + opts.offset[1]) + "px");
				}
				if (opts.position.match(/(left|west)/i)) {
					$tt.css("right", $("body").width() - anchorPosition.left + opts.offset[0] + "px");
				}
				else if (opts.position.match(/center/i)) {
					$tt.css("left", anchorPosition.left - ($tt.outerWidth()/2) + opts.offset[0] + "px");
				}
				else {
					// Define minimum and maximum pixel location for bubble left.
					var minLeft = Math.abs(parseInt($tt.css("margin-left"), 10));
					var maxLeft = $("body").width()  - minLeft;
					// Calculate the new position of the tooltip and save a copy for later.
					newPosition = anchorPosition.left + opts.anchor.outerWidth() + opts.offset[0];
					oldPosition = newPosition;
					// If need be, reposition.
					if (newPosition < minLeft) {
						newPosition = minLeft;
					} else if (newPosition > maxLeft) {
						newPosition = maxLeft;
					}
					// Apply the positioning to the tooltip.
					$tt.css("left", newPosition + "px");
				}
				if (opts.showTip) {
					repositionTip(newPosition - oldPosition, opts);
				}
			} else {
				throw (["Unsupported tooltip definition", opts]);
			}
		};
		$tt.updateOffset = function updateOffset(offset) {
			if (opts.offset !== offset) {
				opts.offset = offset;
				$tt.reposition();
			}
		};
		var repositionTip = function (shiftAmount, opts) {
			var ttWidth = $tt.width(),
				ttPaddingLeft = parseInt($tt.css("padding-left"), 10),
				anchorLeft = opts.anchor.offset().left,
				ttLeft = parseInt($tt.css("left"), 10),
				iconWidth = opts.anchor.width(),
				tipPosition = anchorLeft - ttLeft + (iconWidth/4);
			// If the tooltip is too far to the right, make it point on the corner.
			if (tipPosition > ttWidth + ttPaddingLeft) {
				tipPosition = ttWidth + ttPaddingLeft;
			}
			// Apply the positioning to the tooltip tip.
			$tooltipPoint.css("left", tipPosition + "px");
		};
		var windowResizeHandler = function(){
			$tt.reposition();
		};
		$(window).resize(windowResizeHandler);
		$tt.reposition();
		return $tt;
	};
	return $.tooltip;
});