/*
	Javascript Callout Popup box
	--------------------------

Written by:
 Mikhail Diatchenko
 Nov 2006

Usage:
1) Include popup.js on your page:
	<head>
		<script language="javascript" src="/js_shared/popup.js"></script>
	</head>

Then you've got 2 options
- Option 1) Simple. Creates popup dynamically.

2) Add this code to the HEAD section:
	<script language="javascript">
		Popup.loadSkin("box"); //skin name (folder name in /js_shared/popup_skins/...)

		var popup;

		function init(){

			popup = new Popup();
			popup.init();

			document.onmousedown = function(e) {
				if (!e)
					e = event;

				popup.content.innerHTML = "You clicked on "+e.clientX+"_"+e.clientY;
				popup.showAt(e.clientX, e.clientY);
			}
		}
	</script>

4) Add the following code to BODY onLoad:
	<body onload="init()">

- Option 2) Advanced. Creates popup from HTML on page
2) Add this HTML code snipet to your page:

			<div id="_infoBox" class="map-icon-info" style="display: none">
				<img src="/js_shared/popup_skins/blank.gif" id="pick">
				<table cellpadding="0" cellspacing="0" border="0" id="_infoBoxDataContainer" class="PopupBox">
					<tr>
						<td class=TL></td>
						<td class=TC><div id="popupHeader"></div></td>
						<td class=TR>
							<a href="javascript:popup.hide()"><img src="/js_shared/popup_skins/blank.gif" id="_closeInfo" class="close-info" border="0"></a>
						</td>
					</tr>
					<tr>
						<td class=L></td>
						<td class=C><span id="_infoBoxData">Popup content</span></td>
						<td class=R></td>
					</tr>
					<tr>
						<td class=BL></td>
						<td class=BC><div id="popupFooter"></div></td>
						<td class=BR></td>
					</tr>
				</table>
			</div>

3) Add this code to the HEAD section:
	<script language="javascript">
		Popup.loadSkin("box"); //skin name (folder name in /js_shared/popup_skins/...)

		var popup;

		function init(){

			popup = new Popup();
			popup.loadDesign("_infoBox", "pick", "_infoBoxDataContainer", "_infoBoxData");

			document.onmousedown = function(e) {
				if (!e)
					e = event;

				popup.content.innerHTML = "You clicked on "+e.clientX+"_"+e.clientY;
				popup.showAt(e.clientX, e.clientY);
			}
		}
	</script>

4) Add the following code to BODY onLoad:
	<body onload="init()">

That's it!

There are a number of properties/methods/events available to customise the behaviour:

	Properties:
		width		- (int) wdth of the popup box. Default 250. Set to null for auto width
		minWidth	- (int) minimum width of the popup
		maxHeight	- (int) controls popup maximum height (null - disabled, >0 - fixed max height, <=0 - auto with margins (= -maxHeight/2)), Default null (disabled).
		maxWidth	- (int) controls popup maximum height (null - disabled, >0 - fixed max width, <=0 - auto with margins (= -maxWidth/2)). Default 0.
		x		- (int) x coordinate where popup box was last shown.
		y		- (int) y coordinate where popup box was last shown.
		offset		- (Popup.Point) specified coordinates offset for container, used in calculation if popup fits on page. This is needed that your popup box is in a container what is absolutely positioned. Default (0,0)

		direction	- (PopupDirection) default popup direction. Default is BottomRight;

		content		- (object) popup box content reference. Set content.innerHTML to populate box.
		header		- (object) popup box header reference.
		footer		- (object) popup box tail reference.
			You can access these, but normall no need to:
		container	- (object) popup box container reference.
		tail		- (object) popup box tail reference.
		box			- (object) popup box box reference.

		expandMargin	- (Popup.Offset) margins fox expanding to full screen. Default (50, 50, 50, 50).
		animate		- (bool) controls whether expand()/collapse() is animated.

	Methods:
		init()		- create popup object dynamically (as opposed to HTML in a page)
		loadDesign(containerID, tailID, boxID, contentID)	- loads popup objects from HTML on a page.
		hide()		- hide  the popup box.
		showAt(x, y)	- show popup pinned to a point on a page.
		show()		- restored hidden popup.
		visible()	- returns true is popup is shown.
		expand()	- expands popup box to full screen (with optional margin specified by expandMargin)
		collapse()	- collapses expanded box
		pinTo(object)	- attach popup box to an object, so that on window resize it keeps it position/
		showOnPin()	- show popup box on pinned to an object using pinTo
		calcDynamicSize()	- Recalc width when all images are loaded (width can not be automatically calculated until all images are loaded). Use when popup.content contains images.

	Events:
		onInit(popup)	- fires after the popup was initialised using init()
		onShow(popup)	- fires just before showing the popup, right after the popup is positioned.
		onHide(popup)	- fires just before hiding the popup.
		onOverflow(popup, offset)	- fires when popup box overflows visible window (even after trying all 4 positions).

Examples:

	var popup = new Popup()
	popup.init();
	popup.content.innerHTML = "You clicked on "+e.clientX+"_"+e.clientY;
	document.onmousedown = function(e) {
		if (!e)
			e = event;

		popup.content.innerHTML = "You clicked on "+e.clientX+"_"+e.clientY;
		popup.showAt(e.clientX, e.clientY);
	}

Compatibility:
 The functionality has been tested with the following browsers:
	IE 6 (WinXP)
	Firefox 1.5 (WinXP)
*/

document.write("<script type='text/javascript' src='/js_shared/utils.js'></script>");
document.write("<script type='text/javascript' src='/js_shared/browser.js'></script>");

//this is required to callback functions. read http://www.snook.ca/archives/javascript/javascript_pass/ for more info.
if ( ! Function.prototype.bind ) {
    Function.prototype.bind = function( object ) {
        var __method = this;
        return function() {
            __method.apply( object, arguments );
        };
    };
}

/*
1) the popup box contains 2 elements: box and a tail.

	+------------------------+
    |                        |
    |                        | - box
    |                        |
    +---|   /----------------+
	    |  /
		| /  - tail
		|/
  
2) tail can be of 4 modes:
2.1) Bottom Right
	+------------------------+
    |                        |
    |                        |
    |                        |
    +--------------\   |-----+
	                \  |
		             \ |
		              \|
2.2) Bottom Left
	+------------------------+
    |                        |
    |                        |
    |                        |
    +---|   /----------------+
	    |  /
		| /
		|/


2.3) Top Left
        |\
        | \
        |  \
    +---|   \----------------+
    |                        |
    |                        |
    |                        |
	+------------------------+

2.4) Top Right
                        /|
                       / |
                      /  |
    +----------------/   |---+
    |                        |
    |                        |
    |                        |
	+------------------------+

3) Tail element for each configuration can be of different Popup.Size
*/

// structures ------------------------------------------------------------------
var PopupDirection = new function() {
	this.TopLeft = 0;
	this.TopRight = 1;
	this.BottomRight = 2;
	this.BottomLeft = 3;
}	

Popup.Size = function(w, h) {
	this.width = w;
	this.height = h;
	
	this.toString = function() {
		return this.width + "_" + this.height;
	}

	this.set = function(w, h) {
		this.width = w;
		this.height = h;
	}
}

Popup.Offset = function(l, t, r, b) {
	this.left = l;
	this.top = t;
	this.right = r;
	this.bottom = b;
	
	this.toString = function() {
		return this.left + "_" + this.top + "_" + this.right + "_" + this.bottom;
	}

	this.set = function(l, t, r, b) {
		this.left = l;
		this.top = t;
		this.right = r;
		this.bottom = b;
	}
}

var PopupBoxConfig = new function() {
	this.TailSize = new Popup.Size(0, 0);

	//configures image sizes for each tail mode (see 3))
	this.TailSizeBR = new Popup.Size(0, 0);
	this.TailSizeBL = new Popup.Size(0, 0);
	this.TailSizeTL = new Popup.Size(0, 0);
	this.TailSizeTR = new Popup.Size(0, 0);
	
	//the values are the Popup.Size of shadow from each side for each tail mode
	this.TailBR = new Popup.Offset(0, 0, 1, 12); //left, top, right, bottom
	this.TailBL = new Popup.Offset(10, 0, 0, 10);
	this.TailTL = new Popup.Offset(11, 1, 0, 2);
	this.TailTR = new Popup.Offset(0, -1, 0, 2);
	
	//the values are the Popup.Size of shadow from each side of box. left and right offset also affect tail horisontall offset from
	this.Offset = new Popup.Offset(22, 0, 10, 12);

	//offset from the image edges (including shadows) to the content box (used for calculating auto width)
	this.ContentOffset = new Popup.Offset(10, 10, 10, 10);

	this.DefaultDirection = PopupDirection.BottomRight;
}

var IconConfig = new function() {
	this.IconSize = new Popup.Size(28, 28);
	this.IconOffset = new Popup.Offset(14, 14, 0, 0);
}

// Popup class ---------------------------------------------------------
Popup.loadSkin = function(name) {
	/*
	try
	{
		document.createStyleSheet("/js_shared/popup_skins/style.css");
		document.createStyleSheet("/js_shared/popup_skins/"+name+"/style.css");
	}
	catch(e){}*/
	document.write("<link rel='stylesheet' type='text/css' media='all' href='/js_shared/popup_skins/style.css' />");
	document.write("<link rel='stylesheet' type='text/css' media='all' href='/js_shared/popup_skins/"+name+"/style.css' />");
	document.write("<script type='text/javascript' src='/js_shared/popup_skins/"+name+"/config.js'></script>");
}

Popup.Point = function(x, y) {
	this.x = x;
	this.y = y;
	
	this.toString = function() {
		return this.x + "_" + this.y;
	}
}

function Popup() {
	this.container = null;
	this.tail = null;
	this.box = null;
	this.content = null;
	this.header = null;
	this.footer = null;

	this.width = 250;
	this.minWidth = 250;
	this.maxHeight = null; //null - disabled, >0 - fixed max height, <=0 - auto with margins (= -maxHeight/2)
	this.maxWidth = 0; //null - disabled, >0 - fixed max width, <=0 - auto with margins (= -maxWidth/2)
	this.x = 400;
	this.y = 300;
	this.offset = new Popup.Point(0, 0); //x,y offset

	this.config = PopupBoxConfig;

	this.direction = this.config.DefaultDirection; //BottomRight //default direction of the popup;
	
	// events
	this.onInit = null;	//callback function(popup)
	this.onShow = null;	//callback function(popup)
	this.onHide = null;	//callback function(popup)
	this.onOverflow = null;	//callback function(popup, offset)

	//this.init = function() {
	Popup.prototype.init = function () {
		this.container = document.createElement("DIV");
		this.container.style.display = "none";
		this.container.className = "map-icon-info"
		document.body.appendChild(this.container);

		this.tail = document.createElement("IMG");
		this.tail.src = "/js_shared/popup_skins/blank.gif";
		this.tail.id = "pick";
		this.container.appendChild(this.tail);

		this.box = document.createElement("TABLE");
		this.box.className = "PopupBox";
		this.box.cellPadding = 0;
		this.box.cellSpacing = 0;
		this.box.id = "_infoBoxDataContainer";
		this.container.appendChild(this.box);

		var tbody = document.createElement("TBODY");
		this.box.appendChild(tbody);

		var oRow;
		var oCell;

		oRow = document.createElement("TR");
		tbody.appendChild(oRow);
			
			oCell = document.createElement("TD");
			oRow.appendChild(oCell);
			oCell.className = "TL";

			oCell = document.createElement("TD");
			oRow.appendChild(oCell);
			oCell.className = "TC";

				this.header = document.createElement("DIV");
				this.header.id = "popupHeader";
				oCell.appendChild(this.header);

			oCell = document.createElement("TD");
			oRow.appendChild(oCell);
			oCell.className = "TR";

				var closeBtn;
				closeBtn = document.createElement("IMG");
				closeBtn.src = "/js_shared/popup_skins/blank.gif";
				closeBtn.id = "_closeInfo";
				closeBtn.className = "close-info";
				closeBtn.style.cursor = "pointer";
				closeBtn.onclick = this.hide.bind(this)
				oCell.appendChild(closeBtn);

		oRow = document.createElement("TR");
		tbody.appendChild(oRow);
			oCell = document.createElement("TD");
			oRow.appendChild(oCell);
			oCell.className = "L";

			oCell = document.createElement("TD");
			oRow.appendChild(oCell);
			oCell.className = "C";

				this.content = document.createElement("SPAN");
				this.content.id = "_infoBoxData";
				this.content.innerHTML = "[content]";
				oCell.appendChild(this.content);

			oCell = document.createElement("TD");
			oRow.appendChild(oCell);
			oCell.className = "R";

		oRow = document.createElement("TR");
		tbody.appendChild(oRow);
			oCell = document.createElement("TD");
			oRow.appendChild(oCell);
			oCell.className = "BL";

			oCell = document.createElement("TD");
			oRow.appendChild(oCell);
			oCell.className = "BC";

				this.footer = document.createElement("DIV");
				this.footer.id = "popupFooter";
				oCell.appendChild(this.footer);

			oCell = document.createElement("TD");
			oRow.appendChild(oCell);
			oCell.className = "BR";

		if (this.onInit)
		{
			this.onInit(this);
		}
	}

	this.loadDesign = function(containerID, tailID, boxID, contentID) {
		this.container = document.getElementById(containerID);
		this.tail = document.getElementById(tailID);
		this.box = document.getElementById(boxID);
		this.content = document.getElementById(contentID);
	}

	this.hide = function() {
		if (this.onHide)
		{
			this.onHide(this);
		}
		this.container.style.display="none";
	}

	this.showAt = function(x, y) {
		this.x = x;
		this.y = y;
		this.show();
	}

	Popup.prototype.pinTo = function(obj) {
		this._pinnedTo = obj;
		//var pos = new Popup.Point(Utils.getElementLeft(this._pinnedTo), Utils.getElementTop(this._pinnedTo));
		//this.show();

		var thisRef = this;
		if (!this._eventAttached) {
			Utils.attachEvent(window, "resize", function(e){
				//var pos = Utils.getElementPosition(thisRef._pinnedTo);
				var pos = new Popup.Point(Utils.getElementLeft(thisRef._pinnedTo), Utils.getElementTop(thisRef._pinnedTo));
				pos.x += IconConfig.IconOffset.left;
				pos.y += IconConfig.IconOffset.top;
				//if (thisRef.pinAdjust) {
				//	pos.x -= thisRef.pinAdjust.x;
				//	pos.y -= thisRef.pinAdjust.y;
				//}
				thisRef.showAt(pos.x, pos.y);
			});
			this._eventAttached = true;
		}
	}

	Popup.prototype.showOnPin = function() {
		if (!this._pinnedTo)
			return;

		this.x = Utils.getElementLeft(this._pinnedTo);
		this.y = Utils.getElementTop(this._pinnedTo);
		this.x += IconConfig.IconOffset.left;
		this.y += IconConfig.IconOffset.top;
		this.show();
	}

	this._calcWidth = function() {
		var width = Utils.getElementWidth(this.content)+this.config.ContentOffset.left+this.config.ContentOffset.right;
		//if (width>(Utils.getWindowWidth()-(this.config.ContentOffset.left+this.config.ContentOffset.right))) {
		if (width>Utils.getWindowWidth() && this.maxWidth!=null) {
			if (this.maxWidth>0) {
				width = this.maxWidth;
			} else if (this.maxWidth<=0) {
				width = Utils.getWindowWidth() - (this.config.ContentOffset.left+this.config.ContentOffset.right);
			}
		}
		return width;
	}

	this._recalcWidth = function(_width) {
		var width = _width;

		this.content.style.display = "block";
		//this.content.style.overflow = "auto";
		this.content.style.overflowY = "auto";
		this.content.style.overflowX = "hidden";
		
		if (this.width==null) {
			if (!Browser.isIE)
				width = this._calcWidth();
			else
				width += 22; //add vertical scrollbar width so that horisontal scrollbar is hidden
		}

		return width;
	}

	this.show = function() {
		if (!Browser.isIE)
			this.container.style.visibility = 'hidden';

		if (this.maxHeight!=null) {
			//restore styles if changed for automatic height calculation
			this.content.style.display = "inline";
			this.content.style.overflow = "";
			this.content.style.overflowY = "";
			this.content.style.overflowX = "";
			this.content.style.height = "auto";
			this.content.style.width = "auto";
			this.container.style.width = "auto";
		}

		var width;
		if (this.width==null) {
			//workout width from content;
			this.container.style.position = 'absolute';
			this.container.style.top = "-1000px";
			this.container.style.display = 'block';
			this.content.style.width = "auto";

			width = this._calcWidth();
		} else {
			width = this.width;
		}

		if (width<this.minWidth)
			width = this.minWidth;

		if (this.maxHeight!=null) {
			//calculate height to fit to screen
			var height=Utils.getElementHeight(this.content);

			if (this.maxHeight>0 && height>this.maxHeight) {
				this.content.style.height = this.maxHeight+"px";
				width = this._recalcWidth(width);
			} else if (this.maxHeight<=0) {
				var extraHeight = (this.config.Offset.top+this.config.ContentOffset.top
							+this.config.ContentOffset.bottom+this.config.Offset.bottom
							+this.config.TailSizeBR.height+this.config.TailBR.top+this.config.TailBR.bottom-this.maxHeight);
				if (height>(Utils.getWindowHeight()-extraHeight)) {
					this.content.style.height = (Utils.getWindowHeight()-extraHeight)+"px";
					width = this._recalcWidth(width);
				}
			}
		}

		this.container.style.width = width+"px";

		this.container.style.position = 'absolute';
		this.container.style.display = 'block';
		
		this.collapse();
		
		var boxPos = this._calcBoxPos();
		
		this.container.style.top = boxPos.y+"px";
		this.container.style.left = boxPos.x+"px";

		/*
		if (!this.mark) {
			this.mark = document.createElement("DIV");
			document.body.appendChild(this.mark);
			this.mark.style.display = "block";
			this.mark.style.position = "absolute";
			this.mark.style.padding = 0;
			this.mark.style.border = "2px solid yellow";
			this.mark.style.zIndex = 10000;
			this.mark.style.width = "1px";
			this.mark.style.height = "1px";
		}
		this.mark.style.top = this.y-2+"px";
		this.mark.style.left = this.x-2+"px";
		*/
	
		if (this.onShow)
		{
			this.onShow(this);
		}

		this.container.style.display = 'block';	
		this.container.style.visibility = 'visible';
	}

	/* Support function.
		Width can not be automatically calculated until all images are loaded
		Recalc width when all images are loaded.
		Use when popup.content contains images.
	*/
	Popup.prototype.calcDynamicSize = function() {
		//if (Browser.isIE)
		//	return;
		var imgs = this.content.getElementsByTagName("IMG");
		var _this = this;
		for (var i=0; i<imgs.length; i++) {
			//Utils.attachEvent(imgs[i], "load", this._onLoadImage.bind(this, imgs[i]));
			var _img = imgs[i];
			Utils.attachEvent(imgs[i], "load", function(e) { _this._onLoadImage(e, _img); });

		}
	}

	Popup.prototype._onLoadImage = function(e, img) {
		/*if (!e) {
			e = event;
		}*/
		var _this = this;
		Utils.removeEvent(img, "load", function(e) { _this._onLoadImage(e, img); });
		this.show();
	}

	this.visible = function() {
		return (this.container.style.display != 'none');
	}

	this._getTailHeight = function(direction) {
		if (direction == PopupDirection.TopLeft) {
			return (this.config.TailSizeBR.height - this.config.TailBR.bottom - this.config.Offset.bottom);
		}
		else if (direction == PopupDirection.TopRight) {
			return (this.config.TailSizeBL.height - this.config.TailBL.bottom - this.config.Offset.bottom);
		}
		else if (direction == PopupDirection.BottomLeft) {
			return (this.config.TailSizeTR.height - this.config.TailTR.top-this.config.Offset.top);
		}
		else {
			return (this.config.TailSizeTL.height-this.config.TailTL.top-this.config.Offset.top);
		}
	}

	this._calcBoxPos = function() {
		var pg = new Popup.Point(Utils.getRightPagePos(), Utils.getBottomPagePos());
		var boxOffset = new Popup.Point(0, 0);
		var direction = this.direction;
		
		var containerSize = new Popup.Point(this.container.offsetWidth, this.container.offsetHeight);	
		var margin = 0;//space between popup box and screen edge which triggers swap of box direction
		var boxSize = new Popup.Point(this.box.offsetWidth, this.box.offsetHeight);

		//alert("this.offset:"+this.offset+", this.x:"+this.x+", this.y:"+this.y+", pg:"+pg+", boxSize:"+boxSize);

		var overflow = new Popup.Offset(0, 0, 0, 0);

		overflow.left = -(this.offset.x+this.x-boxSize.x+this.config.Offset.right-margin);
		overflow.bottom = -(pg.y - (this.offset.y+this.y + boxSize.y + this.config.TailSizeTR.height + margin));
		overflow.right = -(pg.x - (this.offset.x+this.x+boxSize.x-this.config.Offset.left+margin));
		overflow.top = -(this.offset.y+this.y - boxSize.y - this.config.TailSizeBR.height - margin);

		//check if fits horisontally
		switch (direction) {
		case PopupDirection.TopLeft:
			if (overflow.left>0 && overflow.right<overflow.left)
				direction = PopupDirection.TopRight; //swap to right
			break;
		case PopupDirection.TopRight:
			if (overflow.right>0 && overflow.left<overflow.right)
				direction = PopupDirection.TopLeft; //swap to left
			break;
		case PopupDirection.BottomLeft:
			if (overflow.left>0 && overflow.right<overflow.left)
				direction = PopupDirection.BottomRight; //swap to right
			break;
		case PopupDirection.BottomRight:
			if (overflow.right>0 && overflow.left<overflow.right)
				direction = PopupDirection.BottomLeft; //swap to left
			break;
		}

		//check if fits vertically
		switch (direction) {
		case PopupDirection.TopLeft:
			if (overflow.top>0 && overflow.bottom<overflow.top)
				direction = PopupDirection.BottomLeft; //swap to bottom
			break;
		case PopupDirection.TopRight:
			if (overflow.top>0 && overflow.bottom<overflow.top)
				direction = PopupDirection.BottomRight; //swap to bottom
			break;
		case PopupDirection.BottomLeft:
			if (overflow.bottom>0 && overflow.tom<overflow.bottom)
				direction = PopupDirection.TopLeft; //swap to top
			break;
		case PopupDirection.BottomRight:
			if (overflow.bottom>0 && overflow.top<overflow.bottom)
				direction = PopupDirection.TopRight; //swap to top
			break;
		}

		//remove negative offsets those that indicate that a side fits(
		//and apply tail offset corrections.
		switch (direction) {
		case PopupDirection.TopLeft:
			overflow.right = -(pg.x - (this.offset.x+this.x + this.config.Offset.right+1*this.config.TailBR.right));
			overflow.bottom = 0;
			overflow.left -= (this.config.TailBR.right + this.config.TailBR.left);
			overflow.top -= (this.config.TailBR.bottom + this.config.TailBR.top);
			break;
		case PopupDirection.TopRight:
			overflow.left = -(this.offset.x+this.x -(this.config.Offset.left+1*this.config.TailBL.left));
			overflow.bottom = 0;
			overflow.right -= (this.config.TailBL.right + this.config.TailBL.left);
			overflow.top -= (this.config.TailBL.bottom + this.config.TailBL.top);
			break;
		case PopupDirection.BottomLeft:
			overflow.right = -(pg.x - (this.offset.x+this.x + this.config.Offset.right+1*this.config.TailTR.right));
			overflow.top = 0;
			overflow.left -= (this.config.TailTR.right + this.config.TailTR.left);
			overflow.bottom -= (this.config.TailTR.bottom + this.config.TailTR.top);
			break;
		case PopupDirection.BottomRight:
			overflow.left = -(this.offset.x+this.x -(this.config.Offset.left+1*this.config.TailTL.left));
			overflow.top = 0;
			overflow.bottom -= (this.config.TailTL.bottom + this.config.TailTL.top);
			overflow.right -= (this.config.TailTL.right + this.config.TailTL.left);
			break;
		}

		if (overflow.top>0 || overflow.bottom>0 || overflow.left>0 || overflow.right>0) {
			if (this.onOverflow) {
				this.onOverflow(this, overflow);
			}
		}

		//must call this after onOverflow so that any modifications of this.x & this.y in a callback are applied.
		var pos = new Popup.Point(this.x, this.y);

		boxOffset.x = 0;
		boxOffset.y = 0;

		this._setupTail(direction, containerSize);

		switch (direction) {
		case PopupDirection.TopLeft:
			boxOffset.x = - containerSize.x + this.config.Offset.right+this.config.TailBR.right;
			boxOffset.y = - containerSize.y - this.config.TailSizeBR.height + this.config.Offset.bottom + this.config.TailBR.bottom;
			break;
		case PopupDirection.TopRight:
			boxOffset.x = - this.config.Offset.left-this.config.TailBL.left;
			boxOffset.y = - containerSize.y - this.config.TailSizeBL.height + this.config.Offset.bottom + this.config.TailBL.bottom;
			break;
		case PopupDirection.BottomLeft:
			boxOffset.x = - containerSize.x + this.config.Offset.right+this.config.TailTR.right;
			boxOffset.y = this.config.TailSizeTR.height - this.config.TailTR.top-this.config.Offset.top;
			break;
		case PopupDirection.BottomRight:
			boxOffset.x = -this.config.Offset.left-this.config.TailTL.left;
			boxOffset.y = this.config.TailSizeTL.height-this.config.TailTL.top-this.config.Offset.top;
			break;
		}
		
		pos.x += boxOffset.x;
		pos.y += boxOffset.y;

		//alert("this.container.style.width:"+this.container.style.width+", pg:"+pg+", containerSize:"+containerSize+", boxSize:"+boxSize+", pos:"+pos);

		return pos;
	}

	this._setupTail = function(direction, containerSize) {	
		if (!this.tail)
			return;
		
		switch (direction) {
		case PopupDirection.TopLeft:
			this.tail.className = "TailBR";
			//this.tail.src = '/images/this.tail/pointer_br.png';
			this.tail.style.left = (containerSize.x - this.config.TailSizeBR.width-this.config.Offset.right)+"px";
			this.tail.style.top = (containerSize.y-this.config.Offset.bottom-this.config.TailBR.top)+"px";// - 9;//pkSize.y - 2;
			break;
		case PopupDirection.TopRight:
			this.tail.className = "TailBL";
			//this.tail.src = '/images/this.tail/pointer_bl.png';
			this.tail.style.left = (this.config.Offset.left)+"px";
			this.tail.style.top = (containerSize.y-this.config.Offset.bottom-this.config.TailBL.top)+"px";// - 9;//pkSize.y - 2;
			break;
		case PopupDirection.BottomLeft:
			this.tail.className = "TailTR";
			//this.tail.src = '/images/this.tail/pointer_tr.png';
			this.tail.style.left = (containerSize.x - this.config.TailSizeTR.width-this.config.Offset.right)+"px";	//pkSize.x;
			this.tail.style.top = (0 - this.config.TailSizeTR.height+this.config.TailTR.bottom+this.config.Offset.top)+"px";// - pkSize.y+6;
			break;
		case PopupDirection.BottomRight:
			this.tail.className = "TailTL";
			//this.tail.src = '/images/this.tail/pointer_tl.png';
			//is this.tail.height instead of this.config.TailSizeTL.height????
			this.tail.style.left = (this.config.Offset.left)+"px";
			this.tail.style.top = (0 - this.config.TailSizeTL.height+this.config.TailTL.bottom+this.config.Offset.top)+"px";//pkSize.y+6;
			break;
		}

	}

	this.expand = function() {
		if (!this._expanded) {
			this.expandMargin = new Popup.Offset(50, 50, 50, 50);
			this._oldWidth = this.container.style.width;
			this._oldHeight = this.box.style.height;
			this._oldLeft = this.container.style.left;
			this._oldTop = this.container.style.top;
		}

		this.tail.style.display = "none"; //hide tail;

		if (this.animate) {
			this._setupAnimation();
			this._startAnimation(); 
		} else
			this._expand();

		this._expanded = true;
	}

	this._expand = function() {
		this.container.style.left = (Utils.getLeftPagePos()+this.expandMargin.left)+"px";
		this.container.style.top = (Utils.getTopPagePos()+this.expandMargin.top)+"px";

		this.container.style.width = (Utils.getRightPagePos()-Utils.getLeftPagePos()-this.expandMargin.right-this.expandMargin.left)+"px";
		this.box.style.height = (Utils.getBottomPagePos()-Utils.getTopPagePos()-this.expandMargin.bottom-this.expandMargin.top)+"px";
	}

	this._setupAnimation = function() {
		if (!this.animation)
		{
			this.animation = new function(){};
		}
		if (this._expanded) {
			this.animation._startLeft = this.animation._endLeft;
			this.animation._startTop = this.animation._endTop;
			this.animation._startWidth = this.animation._endWidth;
			this.animation._startHeight = this.animation._endHeight;
		} else {
			this.animation._startLeft = Utils.getElementLeft(this.container);
			this.animation._startTop = Utils.getElementTop(this.container);
			this.animation._startWidth = Utils.getElementWidth(this.container);
			this.animation._startHeight = Utils.getElementHeight(this.box);
		}

		this.animation._endLeft = Utils.getLeftPagePos()+this.expandMargin.left;
		this.animation._endTop = Utils.getTopPagePos()+this.expandMargin.top;
		this.animation._endWidth = Utils.getRightPagePos()-Utils.getLeftPagePos()-this.expandMargin.right-this.expandMargin.left;
		this.animation._endHeight = Utils.getBottomPagePos()-Utils.getTopPagePos()-this.expandMargin.bottom-this.expandMargin.top;

		this.animation._steps = 10;
		this.animation._step = 0;
	}

	Popup.prototype._startAnimation = function () {

		this.animation._intervalID = setInterval(this._stepAnimation.bind(this), 10);
	}

	Popup.prototype._stepAnimation = function () {
		var a = this.animation;
		a._step++;
		if (a._step<a._steps) {
			this.container.style.left = (a._startLeft+(a._endLeft-a._startLeft)/a._steps*a._step)+"px";
			this.container.style.top = (a._startTop+(a._endTop-a._startTop)/a._steps*a._step)+"px";

			this.container.style.width = (a._startWidth+(a._endWidth-a._startWidth)/a._steps*a._step)+"px";
			this.box.style.height = (a._startHeight+(a._endHeight-a._startHeight)/a._steps*a._step)+"px";
		} else
			this._endAnimation();
	}

	Popup.prototype._endAnimation = function () {
		clearInterval(this.animation._intervalID);

		this.container.style.left = this.animation._endLeft+"px";
		this.container.style.top = this.animation._endTop+"px";

		this.container.style.width = this.animation._endWidth+"px";
		this.box.style.height = this.animation._endHeight+"px";

		if (!this._expanded)
			this.tail.style.display = "block";
	}

	this.collapse = function() {
		if (!this._expanded)
			return;

		this._expanded = false;

		if (this.animate) {
			this.animation._startLeft = this.animation._endLeft;
			this.animation._startTop = this.animation._endTop;
			this.animation._startWidth = this.animation._endWidth;
			this.animation._startHeight = this.animation._endHeight;

			this.animation._endLeft = this._oldLeft.replace("px", "");
			this.animation._endTop = this._oldTop.replace("px", "");
			this.animation._endWidth = this._oldWidth.replace("px", "");
			this.animation._endHeight = this._oldHeight.replace("px", "");

			this.animation._step = 0;

			this._startAnimation();
		} else {
			this.tail.style.display = "block";

			this.container.style.width = this._oldWidth;
			this.box.style.height = this._oldHeight;
			this.container.style.left = this._oldLeft;
			this.container.style.top = this._oldTop;
		} 
	}
}
