function createDelegate(func, aThis) {
	var ret = function () {
		arguments.callee.func.apply(arguments.callee.aThis, arguments);
	}
	ret.func = func;
	ret.aThis = aThis || window;
	return ret;
}

function addEvent(target, type, listener, aThis) {
	if (target.addEventListener) {
		if (target === window && type == "load") {
			if (window.opera || navigator.userAgent.indexOf("Gecko/") != -1) {
				target = document;
			}
			if (navigator.userAgent.indexOf("Gecko/") != -1) {
				type   = "DOMContentLoaded";
			}
		}
		var delegate = createDelegate(listener, aThis || target);
		target.addEventListener(type, delegate, false);
		var remover = function() {
			target.removeEventListener(type,     delegate, false);
			window.removeEventListener("unload", remover,  false);
		}
		window.addEventListener("unload", remover, false);
	} else if (attachEvent) {
		var delegate = createDelegate(listener, aThis || target);
		target.attachEvent("on" + type, delegate);
		var remover = function() {
			target.detachEvent("on" + type, delegate);
			window.detachEvent("onunload",  remover);
		}
		window.attachEvent("onunload", delegate);
	} else {
		var delegate = createDelegate(listener, aThis || target);
		if (target["on" + type]) {
			var _func    = createDelegate(target["on" + type], target);
			var listener = createDelegate(
				function(e) {
					this._oldFunc(e);
					this._newFunc(e);
				},
				{
					_oldFunc : _func,
					_newFunc : delegate
				}
			);
			target["on" + type] = listener;
		} else {
			target["on" + type] = delegate;
		}
		addEvent(window, "unload", function() { this["on" + type] = null }, target);
	}
}

function rolloverImage(node) {
	this.node = node;
	this.defaultSrc  = node.getAttribute("src");
	this.cache = {};
}
rolloverImage.prototype.reset = function() {
	this.swap(this.defaultSrc);
}
rolloverImage.prototype.swap = function(src) {
	this.node.src = src;
}
rolloverImage.prototype.swapById = function(id) {
	this.node.src = this.cache[id] ? (this.cache[id].src || this.defaultSrc) : this.defaultSrc;
}
rolloverImage.prototype.preload = function(src) {
	this.cache[src] = new Image;
	this.cache[src].src = src;
}
rolloverImage.prototype.preloadById = function(id) {
	var src = this.defaultSrc.replace(/\/([^.]+)(\.[^?#\/]+)(\?[^#]*)?(#.*)?$/, function(){
		return "/" + arguments[1] + "_" + id + arguments[2];
	});
	this.cache[id] = new Image;
	this.cache[id].src = src;
}

function floatingPanel(node, area, imgNode) {
	this.node         = document.createElement("ins");
	this.area         = area;
	this.imgNode      = imgNode;
	this.shadow       = document.createElement("ins");
	this.shadowHeader = document.createElement("div");
	this.shadowBody   = document.createElement("div");
	this.shadowFooter = document.createElement("div");
	this.offset       = {
		x : -85,
		y : -10
	}
	this.moveOffset   = {
		x : 0,
		y : 10
	}
	this.duration = 300;
	this.timer = null;
	this._currentTime = 0;
	this._fromPosition = {
		x : 0,
		y : 0
	}
	this._toPosition = {
		x : 0,
		y : 0
	}
	this.init(node, area, imgNode);
}
floatingPanel.prototype.init = function(node) {
	this.node.appendChild(node);

	document.body.appendChild(this.shadow);
	this.shadow.setAttribute("class",     "pseudo-panel-shadow");
	this.shadow.setAttribute("className", "pseudo-panel-shadow");

	this.shadow.appendChild(this.shadowHeader);
	this.shadowHeader.setAttribute("class",     "shadow-header");
	this.shadowHeader.setAttribute("className", "shadow-header");

	this.shadow.appendChild(this.shadowBody);
	this.shadowBody.setAttribute("class",     "shadow-body");
	this.shadowBody.setAttribute("className", "shadow-body");

	this.shadow.appendChild(this.shadowFooter);
	this.shadowFooter.setAttribute("class",     "shadow-footer");
	this.shadowFooter.setAttribute("className", "shadow-footer");

	document.body.appendChild(this.node);
	this.node.setAttribute("class",     "pseudo-panel");
	this.node.setAttribute("className", "pseudo-panel");

	this.node.style.position = "absolute";

	var center = this.getAreaCenter();
	this._fromPosition.x = center.x;
	this._fromPosition.y = center.y;
	this._toPosition.x   = center.x;
	this._toPosition.y   = center.y;
	this.hide();
}
floatingPanel.prototype.getAreaCenter = function() {
	var pos = {
		x : 0,
		y : 0
	};
	var area    = this.area;
	var imgNode = this.imgNode;
	if (area && imgNode) {
		var coords = area.getAttribute("coords").split(/,/g);
		for (var i = 0, n = coords.length; i < n; i++) {
			if (i % 2 == 0) {
				pos.x += parseInt(coords[i]);
			} else {
				pos.y += parseInt(coords[i]);
			}
		}
		var offset = {
			x : imgNode.offsetLeft,
			y : imgNode.offsetTop
		}
		var op = imgNode.offsetParent;
		while (op) {
			offset.x += op.offsetLeft;
			offset.y += op.offsetTop;
			op = op.offsetParent;
		}
		pos.x = pos.x / (coords.length / 2) + offset.x + this.offset.x;
		pos.y = pos.y / (coords.length / 2) + offset.y + this.offset.y;
	}
	return pos;
}
floatingPanel.prototype.show = function(e) {
	this.clearTimer();

	var area    = this.area;
	var imgNode = this.imgNode;
	var pos = {
		x : 0,
		y : 0
	};
	if (e) {
		pos.x = (e.pageX || (document.body.scrollLeft + e.x) || 0) + this.offset.x;
		pos.y = (e.pageY || (document.body.scrollTop  + e.y) || 0) + this.offset.y;
	} else if (area && imgNode) {
		pos = this.getAreaCenter();
	}

	this._fromPosition.x = pos.x + this.moveOffset.x;
	this._fromPosition.y = pos.y + this.moveOffset.y;
	this._toPosition.x   = pos.x;
	this._toPosition.y   = pos.y;
	this.moveTo(this._fromPosition.x, this._fromPosition.y);

	this.node.style.display   = "block";
	this.shadow.style.display = "block";

	this.shadow.style.width       = (this.node.offsetWidth  + 4) + "px";
	this.shadow.style.height      = (this.node.offsetHeight + 5) + "px";
	if (navigator.userAgent.indexOf("MSIE") != -1 && window.ActiveXObject && !window.opera) {
		this.shadowHeader.style.width  = this.node.offsetWidth  + "px";
		this.shadowHeader.style.height = this.node.offsetHeight + "px";
		this.shadowBody.style.width    = (this.node.offsetWidth  - 5) + "px";
		this.shadowBody.style.height   = (this.node.offsetHeight - 4) + "px";
	} else {
		this.shadowBody.style.height  = (this.node.offsetHeight - 5) + "px";
	}

	this.start = new Date;
	this.timer = window.setInterval(
		createDelegate(
			function(){
				var from = this._fromPosition;
				var to   = this._toPosition;

				this._currentTime = Math.min((new Date) - this.start, this.duration);
				this.setOpacity(this.easing(this._currentTime, 0, 100, this.duration));
				this.moveTo(
					this.easing(this._currentTime, from.x, to.x - from.x, this.duration),
					this.easing(this._currentTime, from.y, to.y - from.y, this.duration)
				);
				if (this._currentTime >= this.duration) {
					this.clearTimer();
				}
			},
			this
		),
		1
	);
}
floatingPanel.prototype.hide = function() {
	this.clearTimer();
	this.start = new Date;
	this.timer = window.setInterval(
		createDelegate(
			function(){
				var from = this._fromPosition;
				var to   = this._toPosition;

				this._currentTime = Math.max(this._currentTime - ((new Date) - this.start), 0);
				this.setOpacity(this.easing(this._currentTime, 0, 100, this.duration));
				this.moveTo(
					this.easing(this._currentTime, from.x, to.x - from.x, this.duration),
					this.easing(this._currentTime, from.y, to.y - from.y, this.duration)
				);
				if (this._currentTime <= 0) {
					this.shadow.style.display = this.node.style.display = "none";
					this.clearTimer();
				}
			},
			this
		),
		1
	);
}
floatingPanel.prototype.easing = function(t, b, c, d) {
	if (t >= d) {
		return b + c;
	}
	if ((t /= d / 2) < 1) return c / 2 * t * t * t + b;
	return c / 2 *((t -= 2) * t * t + 2) + b;
}
floatingPanel.prototype.setOpacity = function(opacity) {
	if (navigator.userAgent.indexOf("MSIE") != -1 && window.ActiveXObject && !window.opera) {
		this.node.style.filter  = this.shadow.style.filter  = 'alpha(opacity=' + Math.ceil(opacity) + ')';
	} else {
		this.node.style.opacity = this.shadow.style.opacity = Math.ceil(opacity) / 100;
	}
}
floatingPanel.prototype.moveTo = function(x, y) {
	this.node.style.left = this.shadow.style.left = Math.ceil(x) + "px";
	this.node.style.top  = this.shadow.style.top  = Math.ceil(y) + "px";
}
floatingPanel.prototype.clearTimer = function(noAnimation) {
	if (this.timer) {
		window.clearInterval(this.timer);
		this.timer = null;
	}
}

function panelSelector() {
	this.items = {};
	this.current = null;
}
panelSelector.prototype.appendPanel = function(id, panel) {
	this.items[id] = panel;
}
panelSelector.prototype.select = function(id, e) {
	if (this.current && this.current != this.items[id]) {
		this.current.hide();
	}
	if (this.current != this.items[id]) {
		this.items[id].show(e);
		this.current = this.items[id];
	}
}
panelSelector.prototype.unselect = function() {
	if (this.current) {
		this.current.hide();
	}
	this.current = null;
}

addEvent(
	window,
	"load",
	function() {
		var imgNode = document.getElementById("map");
		if (!imgNode) return;

		var img = new rolloverImage(imgNode);

		var map = document.getElementsByName("area-map")[0];
		if (!map) return;

		var area = map.getElementsByTagName("area");
		if (!area.length) return;

		var selector = new panelSelector;

		var controller = {
			imgNode  : imgNode,
			img      : img,
			map      : map,
			area     : area,
			selector : selector
		};

		addEvent(
			document,
			"click",
			function(e) {
				var imgNode  = this.imgNode;
				var img      = this.img;
				var map      = this.map;
				var area     = this.area;
				var selector = this.selector;

				if (!e) {
					e = window.event;
				}
				var target = e.srcElement || e.target;
				if (target && target !== imgNode) {
					for (var i = 0, n = area.length; i < n; i++) {
						if (area[i] === target) return;
					}
					var checkTarget = target;
					while (checkTarget) {
						if ((" " + checkTarget.className + " ").indexOf(" pseudo-panel ") != -1) {
							return;
						}
						checkTarget = checkTarget.parentNode;
					}
					img.reset();
					selector.unselect();
				}
			},
			controller
		);

		addEvent(
			imgNode,
			"mouseout",
			function(e) {
				var imgNode  = this.imgNode;
				var img      = this.img;
				var map      = this.map;
				var area     = this.area;
				var selector = this.selector;

				if (!e) {
					e = window.event;
				}
				var target = e.toElement || e.relatedTarget;
				if (target && target !== imgNode) {
					for (var i = 0, n = area.length; i < n; i++) {
						if (area[i] === target) return;
					}
					var checkTarget = target;
					while (checkTarget) {
						if ((" " + checkTarget.className + " ").indexOf(" pseudo-panel ") != -1 || (" " + checkTarget.className + " ").indexOf(" pseudo-panel-shadow ") != -1) {
							return;
						}
						checkTarget = checkTarget.parentNode;
					}
					img.reset();
					selector.unselect();
				}
			},
			controller
		);

		for (var i = 0, n = area.length; i < n; i++) {
			(function(area, controller) {
				area.setAttribute("alt", "");
				var id    = area.getAttribute("href").split("#")[1];
				var panel = new floatingPanel(document.getElementById(id), area, controller.imgNode);
				selector.appendPanel(id, panel);
				controller.img.preloadById(id);
				addEvent(
					panel.node,
					"mouseout",
					function(e) {
						var imgNode  = this.imgNode;
						var img      = this.img;
						var map      = this.map;
						var area     = this.area;
						var selector = this.selector;

						if (!e) {
							e = window.event;
						}
						var target = e.toElement || e.relatedTarget;
						if (target && target !== imgNode) {
							for (var i = 0, n = area.length; i < n; i++) {
								if (area[i] === target) return;
							}
							var checkTarget = target;
							while (checkTarget) {
								if ((" " + checkTarget.className + " ").indexOf(" pseudo-panel ") != -1 || (" " + checkTarget.className + " ").indexOf(" pseudo-panel-shadow ") != -1) {
									return;
								}
								checkTarget = checkTarget.parentNode;
							}
							img.reset();
							selector.unselect();
						}
					},
					controller
				);
				addEvent(
					area,
					"mouseover",
					function(e) {
						if (!e) {
							e = window.event;
						}
						this.img.swapById(id);
						this.selector.select(id, e);
					},
					controller
				);
				addEvent(
					area,
					"focus",
					function(e) {
						if (!e) {
							e = window.event;
						}
						this.img.swapById(id);
						this.selector.select(id);
					},
					controller
				);
			})(area[i], controller);
		}
	}
);

document.write('<link rel="stylesheet" type="text/css" href="css/areamap.css">');

