/**
 * The Zapatec DHTML Menu
 *
 * Copyright (c) 2004-2005 by Zapatec, Inc.
 * http://www.zapatec.com
 * 1700 MLK Way, Berkeley, California,
 * 94709, U.S.A.
 * All rights reserved.
 *
 * Windows Widget
 * $$
 *
 */

/**
 * The Window object constructor.  Call it, for example, like this:
 *
 * \code
 *   var win = new Zapatec.Window({
 *   	showResize : false
 *   });
 * \endcode
 *
 * The above creates a new Window object.  The Window isn't displayed
 * instantly; using the "win" variable, the programmer can now set certain
 * configuration variables, hook his own event handlers and then display the
 * window using Zapatec.Window.create() and Zapatec.Window.show().
 *
 * @param config [object] - all parameters are passed as the properties of this object.
 * 
 * Constructor recognizes the following properties of the config object
 * \code
 *    prop. name     | description
 *  -------------------------------------------------------------------------------------------------
 *   showMinButton   | whether to show minimize button (default true).
 *   showMaxButton   | whether to show maximize button (default true).
 *   showCloseButton | whether to show close button (default true).
 *   showStatus      | whether to show status bar text (default true).
 *   showResize      | whether to show resize icon (default true).
 *   raiseOnlyOnTitle| whether to raize when clicking on title or on the whole body of the created window (default true).
 *   canDrag         | whether you can drag the window (default true).
 *   modal           | if true modal window will be created (default false).
 *   onClose         | custom handler, will be called when window is closed.
 *   onRestore       | custom handler, will be called when restore button is clicked.
 *   onMinimize      | custom handler, will be called when min button is clicked.
 *   onMaximize      | custom handler, will be called when max button is clicked.
 *   onShow          | custom handler, will be called when show method is called.
 *   onHide          | custom handler, will be called when hide method is called.
 *   onResize        | custom handler, will be called when window is resized.
 *   onRaise         | custom handler, will be called when window is raized.
 *   onContentLoad   | custom handler, will be called when content is loaded.
 *   minWidth        | minimal width of the window.
 *   minHeight       | minimal height of the window.
 *   
 * \endcode
 */
Zapatec.Window = function (config) {
	this.winDiv = null;
	this.titleArea = null;
	this.titleText = null;
	this.minButton = null;
	this.maxButton = null;
	this.closeButton = null;
	this.contentArea = null;	
	this.statusArea = null;
	this.resizeArea = null;
	this.winNumber = 0;
	this.config = {};
	this.config.showTitle = true;
	this.config.showRestoreButton = false;
	this.config.state = "simple";
	this.config.titleWidth = 0;
	this.config.contentWidth = 0;
	this.config.statusWidth = 0;
	this.config.heightDiff = 0;
	this.config.left = 0;
	this.config.top = 0;
	this.config.width = 0;
	this.config.height = 0;
	this.setConfig(config);
}

/**
 * \internal This function is called from the constructor, only once, to 
 * store only needed properties of the config object passed to the constructor.
 */
Zapatec.Window.prototype.setConfig = function (config) {
	this.config.showMinButton = (typeof config.showMinButton != "undefined") ? config.showMinButton : true;
	this.config.showMaxButton = (typeof config.showMaxButton != "undefined") ? config.showMaxButton : true;
	this.config.showCloseButton = (typeof config.showCloseButton != "undefined") ? config.showCloseButton : true;
	this.config.showStatus = (typeof config.showStatus != "undefined") ? config.showStatus : true;
	this.config.canResize = (typeof config.showResize != "undefined") ? config.showResize : true;
	this.config.raiseOnlyOnTitle = (typeof config.raiseOnlyOnTitle != "undefined") ? config.raiseOnlyOnTitle : true;
	this.config.canDrag = (typeof config.canDrag != "undefined") ? config.canDrag : true;
	this.config.modal = (typeof config.modal != "undefined") ? config.modal : false;
	this.config.onClose = (typeof config.onClose != "undefined") ? config.onClose : null;
	this.config.onRestore = (typeof config.onRestore != "undefined") ? config.onRestore : null;
	this.config.onMaximize = (typeof config.onMaximize != "undefined") ? config.onMaximize : null;
	this.config.onMinimize = (typeof config.onMinimize != "undefined") ? config.onMinimize : null;
	this.config.onShow = (typeof config.onShow != "undefined") ? config.onShow : null;
	this.config.onHide = (typeof config.onHide != "undefined") ? config.onHide : null;
	this.config.onResize = (typeof config.onResize != "undefined") ? config.onResize : null;
	this.config.onRaise = (typeof config.onRaise != "undefined") ? config.onRaise : null;
	this.config.minWidth = (typeof config.minWidth != "undefined") ? config.minWidth : 120;
	this.config.minHeight = (typeof config.minHeight != "undefined") ? config.minHeight : 80;
	this.onContentLoad = (typeof config.onLoad != "undefined") ? config.onLoad : function () {};
}

/**
 * This is a setup function for Window object.
 *
 * It gathers some mostly common routines when seting up the Window object on your page.
 * For example it creates the simple window and shows it, or creates the popup window.
 * Mostly in all cases (except popup window) it will be initialy shown. Possible enhancement
 * is to add a property to control the initial state of the window (including minimized, maximized, etc)
 *
 * @param config [object] - all parameters are passed as the properties of this object. Many of them are 
 * the same as for the constructor.
 * 
 * Function recognizes the following properties of the config object (duplicated properties are listed in 
 * the constructor description so are not included here):
 * \code
 *    prop. name   | description
 *  -------------------------------------------------------------------------------------------------
 *   popup         | if it is set than window will be a popup window, triggered by the element you passed in this variable.
 *   triggerEvent  | if popup is set than this defines which event of the trigger element will force the window to popup. 
 *                 | Possible values: click, mousemove, mouseover, or any DOM event name.
 *   align         | align of the popup window relational to the trigger object. For information on values see the Zapatec.Window.prototype.showAtElement function description
 *   width         | initial width of the window in pixels.
 *   height        | initial height of the window in pixels.
 *   left          | initial X coordinate of the window.
 *   top           | initial Y coordinate of the window.
 *   title         | title of the window.
 *   content       | content of the window.
 *   divContent    | id of or "pointer" to the HTML element containing the content for the window.
 *   urlContent    | URL to load the content from.
 *   
 * \endcode
 */
Zapatec.Window.setup = function (config) {
	if (!config) config = {};
	if (config.popup) {
		var win = new Zapatec.Window(config);
		if (typeof config.popup == "string") {
			config.popup = document.getElementById(config.popup);
		}
		if (!config.popup) {
			alert("You specified wrong trigger element!");
			win.destroy();
			return;
		}
		if (!config.triggerEvent) {
			config.triggerEvent = "click";
		}
		if (!config.align) {
			config.align = null;
		}
		el = config.popup;
		el["on" + config.triggerEvent] = function (ev) {
			if (!win.winDiv) {	
				win.create(0, 0, config.width || win.config.minWidth, config.height || win.config.minHeight);
				if (config.title) {
					win.setTitle(config.title);
				}
				if (config.content) {
					win.setContent(config.content);
				}
				if (config.divContent) {
         		 // Save divContent config option for later use
			        win.config.divContent = config.divContent;
					win.setDivContent(config.divContent);
				}
				if (config.urlContent) {
					win.setContentUrl(config.urlContent);
				}
			}
			if (!win.config.visible) {
				win.showAtElement(this, config.align);
			}
			
			return false;
		}
		
		return;
	} else {
		var win = new Zapatec.Window(config);
		win.create(config.left || 0, config.top || 0, config.width || win.config.minWidth, config.height || win.config.minHeight);
		if (config.title) {
			win.setTitle(config.title);
		}
		if (config.content) {
			win.setContent(config.content);
		}
		if (config.divContent) {
      // Save divContent config option for later use
      win.config.divContent = config.divContent;
			win.setDivContent(config.divContent);
		}
		if (config.urlContent) {
			win.setContentUrl(config.urlContent);
		}
		win.show();
	}
	
	return win;
} 

/**
 * A function that is called to handle mousedown event for our window.
 *
 * This function handles the routines that should be done on mousedown. Target parameter determines
 * whether something was "pushed" and holds that "pushed" element. "pushed" means that mouse was down
 * on that element and was not released. buttonType property of the target element determines the action that will be made.
 * There is one usefull possibility: if the target element has the customMouseDown property and it holds 
 * function, this function will be called except the default action.
 *
 * @param ev [object] - event object.
 * @param win [object] - our window object.
 * @param target [object] - "pushed" element.
 */
Zapatec.Window.mouseDown = function (ev, win, target) {
	if (!win.config.raiseOnlyOnTitle) {
		win.raise();
	} else {
		if (target && ((target.buttonType == "move") || (target.buttonType == "min") || (target.buttonType == "max") || (target.buttonType == "close") || (target.buttonType == "restore"))) {
			win.raise();		
		}
	}
	if (target) {
		switch (target.buttonType) {
			case "move" : {
				if (!target.customMouseDown) {
					if (win.config.canDrag && win.config.state != "min" && win.config.state != "max") {
						//win.showStatus('Drag the window', 'temp');
						win.showStatus('', 'temp');
						var posX = ev.pageX || ev.clientX + window.document.body.scrollLeft || 0;
						var posY = ev.pageY || ev.clientY + window.document.body.scrollTop || 0;
						var L = parseInt(win.winDiv.style.left) || 0;
						var T = parseInt(win.winDiv.style.top) || 0;
						win.winDiv.xOffs = (posX - L);
						win.winDiv.yOffs = (posY - T);
						win.titleArea.style.cursor = "move";
					}
				} else {
					target.customMouseDown(ev, win, target);
				}
				break;
			}

			case "resize" : {
				if (!target.customMouseDown) {
					if (win.config.canResize && win.config.state != "min" && win.config.state != "max") {
						win.showStatus('resize the window', 'temp');
						win.winDiv.xOffs = parseInt(win.winDiv.style.left) || 0;
						win.winDiv.yOffs = parseInt(win.winDiv.style.top) || 0;
					}
				} else {
					target.customMouseDown(ev, win, target);
				}
				break;
			}

			case "close" : {
				if (!target.customMouseDown) {
				} else {
					target.customMouseDown(ev, win, target);
				}
				break;
			}

			case "min" : {
				if (!target.customMouseDown) {
				} else {
					target.customMouseDown(ev, win, target);
				}
				break;
			}

			case "max" : {
				if (!target.customMouseDown) {
				} else {
					target.customMouseDown(ev, win, target);
				}
				break;
			}

			case "restore" : {
				if (!target.customMouseDown) {
				} else {
					target.customMouseDown(ev, win, target);
				}
				break;
			}
		}
	}
}

/**
 * A function that is called to handle mousemove event for our window.
 *
 * This function handles the routines that should be done on mousedown. Target parameter determines
 * whether something was "pushed" and holds that "pushed" element. "pushed" means that mouse was down
 * on that element and was not released. buttonType property of the target element determines the action that will be made.
 * There is one usefull possibility: if the target element has the customMouseMove property and it holds 
 * function, this function will be called except the default action.
 *
 * @param ev [object] - event object.
 * @param win [object] - our window object.
 * @param target [object] - "pushed" element.
 */
Zapatec.Window.mouseMove = function (ev, win, target) {
	if (target) {
		switch (target.buttonType) {
			case "move" : {
				if (!target.customMouseMove) {
					if (win.config.canDrag && win.config.state != "min" && win.config.state != "max") {
						var posX = ev.pageX || ev.clientX + window.document.body.scrollLeft || 0;
						var posY = ev.pageY || ev.clientY + window.document.body.scrollTop || 0;
						var L = posX - win.winDiv.xOffs, T = posY - win.winDiv.yOffs;
						win.setPos(L, T);
					}
				} else {
					target.customMouseMove(ev, win, target);
				}
				break;
			}

			case "resize" : {
				if (!target.customMouseMove) {
					if (win.config.canResize && win.config.state != "min" && win.config.state != "max") {
						var posX = ev.pageX || ev.clientX + window.document.body.scrollLeft || 0;
						var posY = ev.pageY || ev.clientY + window.document.body.scrollTop || 0;

						var style = win.winDiv.style;
					
						var newWidth =  posX - win.winDiv.xOffs;
						if (newWidth < win.config.minWidth) { 
							newWidth = win.config.minWidth;
						}
					
						var newHeight = posY - win.winDiv.yOffs - win.config.heightDiff;
						if (newHeight < win.config.minHeight) { 
							newHeight = win.config.minHeight;
						}
						
						win.setSize(newWidth, newHeight);
						if (win.config.onResize) {
							win.config.onResize(win, newWidth, newHeight);
						}
					}
				} else {
					target.customMouseMove(ev, win, target);
				}
				break;
			}
		}
	}
}

/**
 * A function that is called to handle mouseup event for our window.
 *
 * This function handles the routines that should be done on mousedown. Target parameter determines
 * whether something was "pushed" and holds that "pushed" element. "pushed" means that mouse was down
 * on that element and was not released. buttonType property of the target element determines the action that will be made.
 * There is one usefull possibility: if the target element has the customMouseUp property and it holds 
 * function, this function will be called except the default action.
 *
 * @param ev [object] - event object.
 * @param win [object] - our window object.
 * @param target [object] - "pushed" element.
 */
Zapatec.Window.mouseUp = function (ev, win, target, hi) {
	if (target) {
		switch (target.buttonType) {
			case "move" : {
				if (!target.customMouseUp) {
					if (win.config.canDrag) {
						win.showStatus('', 'restore');
						win.titleArea.style.cursor = "default";
					}
				} else {
					target.customMouseUp(ev, win, target);
				}
				break;
			}

			case "resize" : {
				if (!target.customMouseUp) {
					if (win.config.canResize) {
						win.showStatus('', 'resize');
					}
				} else {
					target.customMouseUp(ev, win, target);
				}
				break;
			}

			case "close" : {
				if (!target.customMouseUp) {
					if (target == (ev.srcElement || ev.target)) {
						win.close();
					}
				} else {
					target.customMouseUp(ev, win, target);
				}
				break;
			}

			case "min" : {
				if (!target.customMouseUp) {
					if (target == (ev.srcElement || ev.target)) {
						win.minimize();
					}
				} else {
					target.customMouseUp(ev, win, target);
				}
				break;
			}
			
			case "max" : {
				if (!target.customMouseUp) {
					if (hi) alert(target === (ev.srcElement || ev.target));
					if (target == (ev.srcElement || ev.target)) {
						win.maximize();
					}
				} else {
					target.customMouseUp(ev, win, target);
				}
				break;
			}

			case "restore" : {
				if (!target.customMouseUp) {
					if (target == (ev.srcElement || ev.target)) {
						win.restore();
					}
				} else {
					target.customMouseUp(ev, win, target);
				}
				break;
			}
		}
	}
}

/**
 * A function that is called to handle doubleclick event for our window.
 *
 * This function handles the routines that should be done on mousedown. Target parameter determines
 * whether something was "pushed" and holds that "pushed" element. "pushed" means that mouse was down
 * on that element and was not released. buttonType property of the target element determines the action that will be made.
 *
 * @param ev [object] - event object.
 * @param win [object] - our window object.
 * @param target [object] - "pushed" element.
 */
Zapatec.Window.dblClick = function (ev, win, target) {
	if (target) {
		switch (target.buttonType) {
			case "move" : {
				switch (win.config.state) {
					case "min" : {
						win.restore();
						
						break;
					}
					case "max" : {
						win.restore();
						
						break;
					}
					case "simple" : {
						win.maximize();
						
						break;
					}
				}
				
				break;
			}
		}
	}
}

/**
 * This function assigns event handlers and implements "pushed" element finding.
 *
 * "Pushed" element finding is implemented the following way: all the event handlers see one
 * global variable target. When mouse is down on some element we try to get its buttonType property
 * or seek this property in elements parents. If the element with the buttonType is found it is put
 * into target variable. 
 */
Zapatec.Window.prototype.addEvents = function () {
	var self = this, target = null;
	Zapatec.Utils.addEvent(this.winDiv, "mousedown", function (ev) {
		ev = ev || window.event; 
		target = Zapatec.Utils.getTargetElement(ev);
		while(!target.buttonType && (target != self.winDiv)) {
			target = target.parentNode;
		}
		if (!target.buttonType) target = null;
		Zapatec.Window.mouseDown(ev, self, target);
		if (target) return Zapatec.Utils.stopEvent(ev);
	});
	Zapatec.Utils.addEvent(window.document, "mousemove", function (ev) {
		ev = ev || window.event; 
		Zapatec.Window.mouseMove(ev, self, target);
		if (target) return Zapatec.Utils.stopEvent(ev);
	});
	Zapatec.Utils.addEvent(window.document, "mouseup", function (ev) {
		ev = ev || window.event; 
		Zapatec.Window.mouseUp(ev, self, target);
		target = null;
		if (target) return Zapatec.Utils.stopEvent(ev);
	});
	if (Zapatec.is_gecko) {
		Zapatec.Utils.addEvent(this.winDiv, "click", function (ev) {
			ev = ev || window.event; 
			if (ev.detail > 1) {
				target = Zapatec.Utils.getTargetElement(ev);
				while(!target.buttonType && (target != self.winDiv)) {
					target = target.parentNode;
				}
				if (!target.buttonType) target = null;
				Zapatec.Window.dblClick(ev, self, target);
			}
			target = null;
			if (target) return Zapatec.Utils.stopEvent(ev);
		});
	} else {
		Zapatec.Utils.addEvent(this.winDiv, "dblclick", function (ev) {
			ev = ev || window.event; 
			target = Zapatec.Utils.getTargetElement(ev);
			while(!target.buttonType && (target != self.winDiv)) {
				target = target.parentNode;
			}
			if (!target.buttonType) target = null;
			Zapatec.Window.dblClick(ev, self, target);
			target = null;
			if (target) return Zapatec.Utils.stopEvent(ev);
		});
	}
}

/*
 * \internal
 * For internal use only. Calculates some sizes needed to implement title and status text cutting and content scrolling.
 */
Zapatec.Window.prototype.calculateSizes = function () {
	this.winDiv.style.display = "block";
	if (this.titleArea) {
		//Safari Fix
		this.config.titleWidth = this.config.width - (this.winDiv.offsetWidth - (Zapatec.is_khtml ? this.titleText.firstChild.offsetWidth : this.titleText.offsetWidth));
		//Safari Fix
		if (Zapatec.is_khtml) this.titleText.removeChild(this.titleText.firstChild);
	}
	
	if (this.contentArea) {
		//Safari Fix
		this.config.contentWidthDiff = this.winDiv.offsetWidth - (Zapatec.is_khtml ? this.contentArea.firstChild.offsetWidth : this.contentArea.offsetWidth);
		this.config.contentWidth = this.config.width - this.config.contentWidthDiff;
		//Safari Fix
		if (Zapatec.is_khtml) this.contentArea.removeChild(this.contentArea.firstChild);
	}
	
	if (this.statusArea) {
		//Safari Fix
		this.config.statusWidth = this.config.width - (this.winDiv.offsetWidth - (Zapatec.is_khtml ? this.statusArea.firstChild.offsetWidth : this.statusArea.offsetWidth));
		//Safari Fix
		if (Zapatec.is_khtml) this.statusArea.removeChild(this.statusArea.firstChild);
	}

	this.config.heightDiff = this.winDiv.offsetHeight - this.config.height;
	this.winDiv.style.display = "none";
}

/**
 * Creates all HTML elements of the window. This function takes in account
 * this.config object, trough its properties you can disable the following elements:
 *  - The whole title (currently don't work) - this.showTitle property;
 *  - Any of 3 buttons (min, max, close) - this.show(Min|Max|Close)Button property;
 *  - The status area - this.showStatus property;
 *  - The resize icon - this.canResize property;
 * Also calls this.addEvents to assign event handlers to the main div and creates WCH 
 * (http://www.aplus.co.yu/WCH/).
 * This function defines the following properties for HTML elements, needed for event handlers:
 *  - buttonType - one of three buttons or resize icon;
 *
 * @param x [integer] x coordinate.
 * @param y [integer] y coordinate.
 * @param width [integer] width of the window.
 * @param height [integer] height of the window.v
 *
 * @return [object] { x, y } containing the position.
 */
Zapatec.Window.prototype.create = function (x, y, width, height)  {
	if (width == "auto") {
		this.config.autoContentWidth = true;
	} else if (width < this.config.minWidth) {
		width = this.config.minWidth;
	}
	if (height == "auto") {
		this.config.autoContentHeight = true;
	} else if (height < this.config.minHeight) {
		height = this.config.minHeight;
	}
	var noButtons = !((this.config.showMinButton == true) || (this.config.showMaxButton) || (this.config.showCloseButton));
	var config = this.config;
	//creating of the top level div to control the width and position of the window
	var div = this.winDiv = Zapatec.Utils.createElement("div", null, true);
	div.className = "zpWinBack";
	div.style.position = "absolute";
	div.style.width = (this.config.width = parseInt(width, 10) || this.config.minWidth) + "px";
	div.style.display = "none";
	this.config.visible = false;
	this.addEvents();
	
	//creating of another div with zpWin class
	div = Zapatec.Utils.createElement("div", div, true);
	div.className = "zpWin";
	
	//table with all the elements
	var table = Zapatec.Utils.createElement("table", div, true);
	table.border = 0;
	table.cellPadding = "0";
	table.cellSpacing = "0";
	
	var tbody = Zapatec.Utils.createElement("tbody", table, true);
	
	//title area of the window
	if (config.showTitle == true) {
		var tr = this.titleArea = Zapatec.Utils.createElement("tr", tbody);
		tr.buttonType = "move";
		tr.className = "zpWinTitleArea";
		
		//additional cell for ronded borders in title
		var td = Zapatec.Utils.createElement("td", tr);
		div = Zapatec.Utils.createElement("div", td);
		div.innerHTML = "&nbsp;";

		//cell with title text
		this.td = td = Zapatec.Utils.createElement("td", tr);
		td.style.width = "100%";
		
		div = this.titleText = Zapatec.Utils.createElement("div", td);
		div.className = "zpWinTitleText";
		div.style.overflow = "hidden";
		//div.style.height = "100%";
		//Safari Fix
		if (Zapatec.is_khtml) div = Zapatec.Utils.createElement("div", div);
		div.appendChild(document.createTextNode(""));
		
		//cell with minimize button
		td = Zapatec.Utils.createElement("td", tr);
		
		if (config.showMinButton == true) {	
			div = this.minButton = Zapatec.Utils.createElement("div", td);
			div.style.overflow = "hidden";
			div.buttonType = "min";
			div.className = "zpWinMinButton";
		}
		
		//cell with maximize button
		td = Zapatec.Utils.createElement("td", tr);
		
		if (config.showMaxButton == true) {		
			div = this.maxButton = Zapatec.Utils.createElement("div", td);
			div.style.overflow = "hidden";
			div.buttonType = "max";
			div.className = "zpWinMaxButton";
		} 
					
		//cell with close button
		td = Zapatec.Utils.createElement("td", tr);
		
		if (config.showCloseButton == true) {		
			div = this.closeButton = Zapatec.Utils.createElement("div", td);
			div.style.overflow = "hidden";
			div.buttonType = "close";
			div.className = "zpWinCloseButton";
		} else if (noButtons) {
			//a workaround for Gecko's behaviour(we need to create at least one button cell for the window to be shown correctly).
			div = Zapatec.Utils.createElement("div", td);
			div.innerHTML = "&nbsp;";
		}
		tr.firstChild.id = "titleFirstCell";
		tr.lastChild.id = "titleLastCell";
	}
	
	//creating content area
	tr = Zapatec.Utils.createElement("tr", tbody, true);
		
	td = Zapatec.Utils.createElement("td", tr, true);
	td.colSpan = 5;
	td.id = "contentCell";
		
	div = this.contentArea = document.createElement("div");
	td.appendChild(div);
	div.style.height = (this.config.height = parseInt(height, 10) || this.config.minHeight) + "px";
	div.style.overflow = "auto";
	div.className = "zpWinContent";
	//Safari Fix
	if (Zapatec.is_khtml) div = Zapatec.Utils.createElement("div", div);
	div.appendChild(document.createTextNode(""));
		
	//creating of status area
	tr = Zapatec.Utils.createElement("tr", tbody);
	
	td = Zapatec.Utils.createElement("td", tr);
	td.colSpan = 5;
	td.id = "statusCell";
		
	table = Zapatec.Utils.createElement("table", td);
	table.width = "100%";
	table.height = "100%";
	table.cellPadding = "0";
	table.cellSpacing = "0";
	if ((config.showStatus == true) || (config.canResize == true)) {
		table.id = "statusTable";
	} else {
		table.id = "bottomTable";
	}
		
	tbody = Zapatec.Utils.createElement("tbody", table);
		
	tr = Zapatec.Utils.createElement("tr", tbody);
	
	//status text
	td = Zapatec.Utils.createElement("td", tr);
	td.style.verticalAlign = "bottom";
	td.style.width = "100%";
			
	if (config.showStatus == true) {
		div = this.statusArea = Zapatec.Utils.createElement("div", td);
		div.style.overflow = "hidden";
		div.className = "zpWinStatus";
		//Safari Fix
		if (Zapatec.is_khtml) div = Zapatec.Utils.createElement("div", div);
		div.appendChild(document.createTextNode(""));
	}
		
	//resize button
	if (config.canResize == true) {
		td = Zapatec.Utils.createElement("td", tr);
		td.style.verticalAlign = "bottom";
			
		div = this.resizeArea = Zapatec.Utils.createElement("div", td);
		div.style.overflow = "hidden";
		div.buttonType = "resize";
		div.className = "zpWinResize";
	}

	window.document.body.appendChild(this.winDiv);
	//Seting widths of title, content and status elements for IE to proceed overflows.
	this.calculateSizes();
	this.td.style.width = "";
	var size = Zapatec.Utils.getWindowSize(); 
	var br = {};
	if (Zapatec.is_ie) {
		br.y = window.document.body.scrollTop;
		br.x = window.document.body.scrollLeft;
	} else {
		br.y = window.scrollY || 0;
		br.x = window.scrollX || 0;
	}
 	if (x == 'center') { 
 		if (screen.width) { 
 			x = (size.width -  this.config.width)/2 + br.x; 
 		} 
 	} 
 	if (y == 'center') { 
 		if (screen.height) { 
			y = (size.height - (this.config.height + this.config.heightDiff))/2 + br.y; 
 		} 
 	}
	this.show();
	this.winDiv.style.left = (this.config.left = x) + "px";
	this.winDiv.style.top = (this.config.top = y) + "px";
	if (this.titleText) {
		this.titleText.style.width = this.config.titleWidth + "px";
		if (this.config.titleWidth != this.titleText.offsetWidth) {
			this.config.titleWidth -= this.titleText.offsetWidth - this.config.titleWidth;
		} 
	}
	if (this.contentArea) {
		this.contentArea.style.width = this.config.contentWidth + "px";
		if (this.config.contentWidth != this.contentArea.offsetWidth) {
			this.config.contentWidth -= this.contentArea.offsetWidth - this.config.contentWidth;
		}
	}
	if (this.statusArea) {
		this.statusArea.style.width = this.config.statusWidth + "px";
		if (this.config.statusWidth != this.statusArea.offsetWidth) {
			this.config.statusWidth -= this.statusArea.offsetWidth - this.config.statusWidth;
		}
	}
	this.setWidth(parseInt(width, 10) || this.config.minWidth); 
	this.hide();
	
	//Creating WCH
	this.WCH = Zapatec.Utils.createWCH();
	
	//Activating window.
	if (this.config.modal == true) {
		this.modalLayer = Zapatec.Utils.createElement("DIV", document.body);
		var st = this.modalLayer.style;
		st.display = "none";
		st.position = "absolute";
		st.top = br.y + "px";
		st.left = br.x + "px";
		var dim = Zapatec.Utils.getWindowSize();
		st.width = dim.width + "px";
		st.height = dim.height + "px";
		st.zIndex = Zapatec.Window.maxNumber++;
		this.modalLayer.className = "zpWinModal";
		Zapatec.ScrollWithWindow.register(this.modalLayer);
	}
	this.setNumber();
	this.winDiv.style.zIndex = Zapatec.Window.maxNumber;
	Zapatec.Window.winArray.push(this);
	this.setCurrent();
	//alert(document.getElementById("1").innerHTML);
	return true;
}	

// Global that holds the array of all the windows on the page
Zapatec.Window.winArray = [];
// Global that keeps track of max number of windows
Zapatec.Window.maxNumber = 0;
// Global that holds the pointer to the current window
Zapatec.Window.currentWindow = null;
// Global that holds the current position to minimize to
Zapatec.Window.minimizeLeft = 0;
// Global that determines the minimal width of the window
Zapatec.Window.minWinWidth = 120;
// Global that keeps last active window
Zapatec.Window.lastActive = null;

/**
 * \internal 
 * Sorts all the minimized windows at the bottom when one of them was restored to the simple state.
 */
Zapatec.Window.sortMin = function (raised) {
	var place = parseInt(raised.winDiv.style.left, 10), win;
	for (var i in Zapatec.Window.winArray) {
		win = Zapatec.Window.winArray[i];
		if (win && win.config.state == "min") {
			var left = parseInt(win.winDiv.style.left, 10);
			if (left > place) {
				left -= Zapatec.Window.minWinWidth + 5;
				win.winDiv.style.left = left + "px";
				if (win.WCH) win.WCH.style.left = win.winDiv.style.left;
				
			}
		}
	}
	Zapatec.Window.minimizeLeft -= Zapatec.Window.minWinWidth + 5;
}

/*
 * \internal
 * For internal use only.
 * Increment the max number of windows
 */
Zapatec.Window.prototype.setNumber = function() {
	this.winNumber = ++Zapatec.Window.maxNumber;
};

/*
 * \internal
 * For internal use only.
 * Sets the current window
 */

Zapatec.Window.prototype.setCurrent = function(deb) {
	var win = this;
	if (!win.winDiv) {
		return false;
	}
	if (Zapatec.Window.currentWindow && //if it is not the first one
			win != Zapatec.Window.currentWindow) { //and it is not the same one as before
		//Show the previous window as not being the current window anymore
		if (Zapatec.Window.currentWindow.winDiv) {
			Zapatec.Utils.removeClass(Zapatec.Window.currentWindow.winDiv, 'zpWinFront');
			Zapatec.Utils.addClass(Zapatec.Window.currentWindow.winDiv, 'zpWinBack');
			Zapatec.Window.currentWindow.config.active = false;
		}
		if (Zapatec.Window.currentWindow.winDiv && Zapatec.Window.currentWindow.config.state != "min") {
			Zapatec.Window.lastActive = Zapatec.Window.currentWindow;
		} else {
			var zIndex = 0;
			Zapatec.Window.lastActive = null;
			for(i in Zapatec.Window.winArray) {
				if (Zapatec.Window.winArray[i] && Zapatec.Window.winArray[i].winDiv && Zapatec.Window.winArray[i].winDiv.style && (parseInt(Zapatec.Window.winArray[i].winDiv.style.zIndex, 10) > zIndex) && (Zapatec.Window.winArray[i].config.state != "min") && (Zapatec.Window.winArray[i] != win)) {
					zIndex = parseInt(Zapatec.Window.winArray[i].winDiv.style.zIndex, 10);
					Zapatec.Window.lastActive = Zapatec.Window.winArray[i];
				}
			}
		}
	}
	//And set the current window
	Zapatec.Window.currentWindow = win;
	Zapatec.Utils.removeClass(win.winDiv, 'zpWinBack');
	Zapatec.Utils.addClass(win.winDiv, 'zpWinFront');
	win.config.active = true;
	return true;
}

/* 
 * Set the content of a window.
 * @param type [string] the HTML data to set the content to.
 */

Zapatec.Window.prototype.setContent = function(text) {
	if (!this.winDiv) {
		return false;
	}
	if (this.config.autoContentWidth) {
		if (this.contentArea) {
			this.contentArea.style.width = "";
		}
		this.contentArea.parentNode.colSpan = 1;
		this.contentArea.style.overflow = "visible";
	}
	if (this.config.autoContentHeight) {
		if (this.contentArea) {
			this.contentArea.style.height = "";
		}
		this.contentArea.style.overflow = "visible";
	}

	this.contentArea.innerHTML = text;

	if (this.config.autoContentWidth || this.config.autoContentHeight) {
		var shown = false;
		if (this.winDiv.style.display != "block") {
			this.show();
			shown = true;
		}
		var width = this.contentArea.offsetWidth;
		this.contentArea.parentNode.colSpan = 5;
		if (this.config.autoContentWidth) this.setWidth(width + this.config.contentWidthDiff);
		if (this.config.autoContentHeight) this.setHeight(this.contentArea.offsetHeight + 1 + (Zapatec.is_opera ? 4 : 0));
		this.contentArea.style.overflow = "auto";
		if (shown) this.hide();
	}
	return true;
}

/* 
 * Set the content of a window from HTML element(DIV).
 * @param div [string]or [object] the HTML data to set the content to.
 */

Zapatec.Window.prototype.setDivContent = function(div) {
	if (!this.winDiv) {
		return false;
	}
	if (typeof div == "string") {
		div = document.getElementById(div);
	}
	var shown = false;
	if (this.winDiv.style.display != "block") {
		this.show();
		shown = true;
	}
	if (div && this.contentArea) {
		if (this.config.autoContentWidth) {
			if (this.contentArea) {
				this.contentArea.style.width = "";
			}
			this.contentArea.parentNode.colSpan = 1;
			this.contentArea.style.overflow = "visible";
		}
		if (this.config.autoContentHeight) {
			if (this.contentArea) {
				this.contentArea.style.height = "";
			}
			this.contentArea.style.overflow = "visible";
 		}

		var objChild = null;
	    // Remove all previous window content
	    objChild = this.contentArea.firstChild;
	    while (objChild) {
	      this.contentArea.removeChild(objChild);
	      objChild = this.contentArea.firstChild;
	    }
	    // Move all children to the window
	    objChild = div.firstChild;
	    while (objChild) {
	      this.contentArea.appendChild(objChild);
	      objChild = div.firstChild;
	    }

		if (this.config.autoContentWidth || this.config.autoContentHeight) {
			var width = this.contentArea.offsetWidth;
			this.contentArea.parentNode.colSpan = 5;
			if (this.config.autoContentWidth) this.setWidth(width + this.config.contentWidthDiff);
			if (this.config.autoContentHeight) this.setHeight(this.contentArea.offsetHeight + 1 + (Zapatec.is_opera ? 4 : 0));
			this.contentArea.style.overflow = "auto";
			if (shown) this.hide();
		}
	}
	return true;
}

/* 
 * Set the content of a window from url.
 * @param div [string]or [object] the HTML data to set the content to.
 */

Zapatec.Window.prototype.setContentUrl = function(url) {
	if (!this.winDiv) {
		return false;
	}
	var self = this;
	Zapatec.Transport.fetch({
		url : url, 
		onLoad : function (result) {
			//FIXED: <script>s didn't actually were executed on loaded piece of HTML, which I think was a problem
			var text = result.responseText, script, scripts = [], attrs;
			while (script = text.match(/<script([^>]*)>([^<]*)<\/script>/)) {
				text = text.replace(/<script[^>]*>[^<]*<\/script>/, "");
				scripts.push(script);
			}
			self.setContent(text);
			for(i in scripts) {
				// Evaluate code in global scope
				setTimeout(scripts[i][2], 0);
			}
			self.onContentLoad();
		},
		onError : function () {
			alert('Error while fetching data from the server');
		}
	});
	return true;
}

/*
 * Set the title of the window
 * @param type [string] the title to set to
 */ 
Zapatec.Window.prototype.setTitle = function(text) {
	if (!this.winDiv) {
		return false;
	}
	if (text === '') {
		this.titleText.innerHTML = 'Window ' + this.winNumber;
	} else {
		this.titleText.innerHTML = text;
	}
	return true;
}

/**
 * Updates the window "WCH" (windowed controls hider).  A WCH is an
 * "invention" (read: "miserable hack") that works around one of the most
 * common and old bug in Internet Explorer: the SELECT boxes or IFRAMES show on
 * top of any other HTML element.  This function makes sure that the WCH covers
 * correctly the window element and another element if passed.
 */
Zapatec.Window.prototype.updateWCH = function() {
	if (this.WCH && this.WCH.style.bottom != "") {
		this.WCH.style.bottom = "";
	}
	Zapatec.Utils.setupWCH(this.WCH, this.config.left, this.config.top, this.config.width, this.config.height + this.config.heightDiff - 2);
	return true;
}

/**
 * Sets the X coordinate of the window. Needed to synchronize some variables in
 * one place. Also updates the WCH for IE.
 *
 * @param left [integer] - X coordinate.
 */
Zapatec.Window.prototype.setLeft = function(left) {
	if (!this.winDiv) {
		return false;
	}
	if (isNaN(left)) return false;
	(left < 0) && (left = 0);
	this.winDiv.style.left = (this.config.left = left) + "px";
	this.updateWCH();
	return true;
}

/**
 * Sets the Y coordinate of the window. Needed to synchronize some variables in
 * one place. Also updates the WCH for IE.
 *
 * @param top [integer] - Y coordinate.
 */
Zapatec.Window.prototype.setTop = function(top) {
	if (!this.winDiv) {
		return false;
	}
	if (isNaN(top)) return false;
	(top < 0) && (top = 0);
	this.winDiv.style.top = (this.config.top = top) + "px";
	this.updateWCH();
	return true;
}

/**
 * Sets the width of the window. Needed to synchronize some variables in
 * one place. Also updates the WCH for IE.
 *
 * @param width [integer] - width of the window.
 */
Zapatec.Window.prototype.setWidth = function(width) {
	if (!this.winDiv) {
		return false;
	}
	if (isNaN(width)) return false;
	var diff = this.config.width - width;
	if (Zapatec.is_gecko) {
	}
	if (this.titleText) this.titleText.style.width = (this.config.titleWidth -= diff) + "px";
	if (this.contentArea) this.contentArea.style.width = (this.config.contentWidth -= diff) + "px";
	if (this.statusArea) this.statusArea.style.width = (this.config.statusWidth -= diff) + "px";
	this.winDiv.style.width = (this.config.width = width) + "px";
	this.updateWCH();
	return true;
}

/**
 * Sets the height of the window. Needed to synchronize some variables in
 * one place. Also updates the WCH for IE.
 *
 * @param height [integer] - height of the window.
 */
Zapatec.Window.prototype.setHeight = function(height) {
	if (!this.winDiv) {
		return false;
	}
	if (isNaN(height)) return false;
	this.contentArea.style.height = (this.config.height = height) + "px";
	this.updateWCH();
	return true;
}

/**
 * Sets the position of the window. 
 *
 * @param left [integer] - X coordinate.
 * @param top [integer] - Y coordinate.
 */
Zapatec.Window.prototype.setPos = function(left, top) {
	if (!this.winDiv) {
		return false;
	}
	this.setLeft(left);
	this.setTop(top);
	return true;
}

/**
 * Sets the sizes of the window. 
 *
 * @param width [integer] - width of the window.
 * @param height [integer] - height of the window.
 */
Zapatec.Window.prototype.setSize = function(width, height) {
	if (!this.winDiv) {
		return false;
	}
	this.setWidth(width);
	this.setHeight(height);
	return true;
}


/**
 * Sets the sizes and position of the window. 
 *
 * @param left [integer] - X coordinate.
 * @param top [integer] - Y coordinate.
 * @param width [integer] - width of the window.
 * @param height [integer] - height of the window.
 */
Zapatec.Window.prototype.setPosAndSize = function(left, top, width, height) {
	if (!this.winDiv) {
		return false;
	}
	this.setPos(left, top);
	this.setSize(width, height);
	return true;
}

/**
 * Raise this window so that it's above all other.
 * Bring it to the front.
 */ 
Zapatec.Window.prototype.raise = function() {
	if (!this.winDiv) {
		return false;
	}
	if (!this.config.active) {
		Zapatec.Window.maxNumber++; //increment so it's more than all the others
		this.winDiv.style.zIndex = Zapatec.Window.maxNumber;
		this.setCurrent(this);
		if (this.config.onRaise) {
			this.config.onRaise(this);
		}
	}
	return true;
}

/**
 * Sets the status text of the window. 
 *
 * @param mesage [string] - text to be shown.
 * @param mode [string] - currently mode forces to do some additional action when seting the text.
 *                        For example, "temp" means to store the previous value.
 */
Zapatec.Window.prototype.showStatus = function(message, mode) {
	if (!this.winDiv) {
		return false;
	}
	if (this.config.showStatus) {
		switch (mode) {
			case "temp" : {
				this.config.statusText = this.statusArea.innerHTML;
				break;
			}
			
			case "restore" : {
				message = this.config.statusText;
				break;
			}
			
		}
		this.statusArea.innerHTML = message;
	}
	return true;
}

/**
 * Shows the window.
 */ 
Zapatec.Window.prototype.show = function() {
	if (!this.winDiv) {
		return false;
	}
	this.winDiv.style.display = "block";
	if (this.config.modal == true && this.modalLayer) {
		this.modalLayer.style.display = "block";
	}
	this.updateWCH();
	this.config.visible = true;	
	if (this.config.onShow) {
		this.config.onShow(this);
	}
	return true;
}

/**
 * Hides the window.
 */ 
Zapatec.Window.prototype.hide = function() {
	if (!this.winDiv) {
		return false;
	}
	this.winDiv.style.display = "none";
	if (this.config.modal == true && this.modalLayer) {
		this.modalLayer.style.display = "none";
	}
	Zapatec.Utils.hideWCH(this.WCH);
	this.config.visible = false;	
	if (this.config.onHide) {
		this.config.onHide(this);
	}
	return true;
}

/**
 * Minimizes the window.
 */ 
Zapatec.Window.prototype.minimize = function() {
	if (!this.winDiv) {
		return false;
	}
	if (this.config.showMinButton && this.state != "min") {
		var target = this.minButton;
		if (this.contentArea) {
			var style = this.titleArea.nextSibling.style;
			style.display = "none";
		}
		if (this.statusArea || this.resizeArea) {
			style = this.titleArea.nextSibling.nextSibling.style;
			style.display = "none";
		}
		target.buttonType = "restore";
		target.className = "zpWinRestoreButton";
		this.winDiv.style.width = Zapatec.Window.minWinWidth + "px";
		if (this.titleText) this.titleText.style.width = (Zapatec.Window.minWinWidth - (this.config.width - this.config.titleWidth)) + "px";
		this.winDiv.style.left = Zapatec.Window.minimizeLeft + "px";
		
		this.winDiv.style.top = Zapatec.Utils.getWindowSize().height - this.winDiv.offsetHeight;
		this.config.showMinButton = false;
		if (this.config.state == "max") {
			this.config.showMaxButton = true;
			this.maxButton.className = "zpWinMaxButton";
			this.maxButton.buttonType = "max";
		} else {
			this.config.showRestoreButton = true;
		}
		this.config.state = "min";
		if (Zapatec.Window.lastActive) {
			Zapatec.Window.lastActive.setCurrent();
		}
		Zapatec.Utils.setupWCH(this.WCH, Zapatec.Window.minimizeLeft, 0, Zapatec.Window.minWinWidth, this.config.minHeight);
		if (this.WCH) {
			this.WCH.style.top = Zapatec.Utils.getWindowSize().height - this.winDiv.offsetHeight;
		}
		Zapatec.Window.minimizeLeft += Zapatec.Window.minWinWidth + 5;
	} else {
		return false;
	}
	if (this.config.onMinimize) {
		this.config.onMinimize(this);
	}

	return true;
}

/**
 * Maximizes the window.
 */ 
Zapatec.Window.prototype.maximize = function() {
	if (!this.winDiv) {
		return false;
	}
	if (this.config.showMaxButton && this.state != "max") {
		var target = this.maxButton;
		var sizes = Zapatec.Utils.getWindowSize();
		var windowWidth = sizes.width;
		var windowHeight = sizes.height;
		var style = this.winDiv.style;
		style.left = "0px";
		style.top = "0px";
		var diff = this.config.width - windowWidth;
		style.width = windowWidth + "px";
		if (this.titleText) this.titleText.style.width = (this.config.titleWidth - diff) + "px";
		if (this.contentArea) this.contentArea.style.width = (this.config.contentWidth - diff) + "px";
		if (this.statusArea) this.statusArea.style.width = (this.config.statusWidth - diff) + "px";
		this.contentArea.style.height = (windowHeight - this.config.heightDiff) + "px";
		Zapatec.Utils.setupWCH(this.WCH, 0, 0, windowWidth, windowHeight);

		if (this.config.state == "min") {
			if (this.contentArea) {
				var style = this.titleArea.nextSibling.style;
				if (!Zapatec.is_ie) {
					if (style.display != "table-row") {
						style.display = "table-row";
					}
				} else {
					if (style.display != "block") {
						style.display = "block";
					}
				}
			}
			
			if (this.statusArea || this.resizeArea) {
				var style = this.titleArea.nextSibling.nextSibling.style;
				if (!Zapatec.is_ie) {
					if (style.display != "table-row") {
						style.display = "table-row";
					}
				} else {
					if (style.display != "block") {
						style.display = "block";
					}
				}
			}
			this.config.showMinButton = true;
			this.minButton.className = "zpWinMinButton";
			this.minButton.buttonType = "min";
			Zapatec.Window.sortMin(this);
		} else {
			this.config.showRestoreButton = true;
		}
		this.config.showMaxButton = false;
		this.config.state = "max";
		target.buttonType = "restore";
		target.className = "zpWinRestoreButton";
	} else {
		return false;
	}
	if (this.config.onMaximize) {
		this.config.onMaximize(this);
	}
	
	return true;
}

/**
 * Restores the window.
 */ 
Zapatec.Window.prototype.restore = function() {
	if (!this.winDiv) {
		return false;
	}
	if (this.config.showRestoreButton && this.state != "simple") {
		if (this.contentArea) {
			var style = this.titleArea.nextSibling.style;
			if (!Zapatec.is_ie) {
				if (style.display != "table-row") {
					style.display = "table-row";
				}
			} else {
				if (style.display != "block") {
					style.display = "block";
				}
			}
		}
		
		if (this.statusArea || this.resizeArea) {
			var style = this.titleArea.nextSibling.nextSibling.style;
			if (!Zapatec.is_ie) {
				if (style.display != "table-row") {
					style.display = "table-row";
				}
			} else {
				if (style.display != "block") {
					style.display = "block";
				}
			}
		}
		
		this.config.showRestoreButton = false;
		if (this.config.state == "min") {
			var target = this.minButton;
			this.config.showMinButton = true;
			target.buttonType = "min";
			target.className = "zpWinMinButton";
			Zapatec.Window.sortMin(this);
		} else if (this.config.state == "max") {
			var target = this.maxButton;
			this.config.showMaxButton = true;
			target.buttonType = "max";
			target.className = "zpWinMaxButton";
		}
		this.config.state = "simple";
		this.setPosAndSize(this.config.left, this.config.top, this.config.width, this.config.height);
	}

	if (this.config.onRestore) {
		this.config.onRestore(this);
	}
	return true;
}

/**
 * Closes the window. Currently does not destroys the window object, just the HTML part of it
 */ 
Zapatec.Window.prototype.close = function() {
  	if (!this.winDiv) {
		return false;
	}
	// Return content back to the place it was taken from
  if (this.config.divContent && this.contentArea) {
    var objContent = null;
    if (typeof this.config.divContent == 'string') {
      objContent = document.getElementById(this.config.divContent);
    } else if (typeof this.config.divContent == 'object') {
      objContent = this.config.divContent;
    }
    if (objContent) {
      var objChild = this.contentArea.firstChild;
      while (objChild) {
        objContent.appendChild(objChild);
        objChild = this.contentArea.firstChild;
      }
    }
  }
  // Destroy window
	Zapatec.Utils.destroy(this.winDiv);
	Zapatec.Utils.destroy(this.WCH);
	if (this.config.modal == true && this.modalLayer) {
		Zapatec.Utils.destroy(this.modalLayer);
	}
	delete this.winDiv;
	for (i in Zapatec.Window.winArray) {
		if (Zapatec.Window.winArray[i] == this) {
			Zapatec.Window.winArray[i] = null;
		}
	}
	if (Zapatec.Window.lastActive) {
		Zapatec.Window.lastActive.setCurrent();
	}
	if (this.config.onClose) {
		this.config.onClose(this);
	}
	return true;
}

/**
 * Destroy the window.
 */ 
Zapatec.Window.prototype.destroy = function() {
	this.close();
}

/**
 * This function displays the calendar near a given "anchor" element, according
 * to some rules passed in \em opts.  The \em opts argument is a string
 * containing one or 2 letters.  The first letter decides the vertical
 * alignment, and the second letter decides the horizontal alignment relative
 * to the anchor element.  Following we will describe these options; in parens
 * we will use simple descriptions like "top to bottom" which means that the
 * top margin of the calendar is aligned with the bottom margin of the object.
 *
 * \b Vertical align:
 *
 * - T -- the calendar is completely above the element (bottom to top)
 * - t -- the calendar is above the element but might overlap it (bottom to bottom)
 * - C -- the calendar is vertically centered to the element
 * - b -- the calendar is below the element but might overlap it (top to top)
 * - B -- the calendar is completely below the element (top to bottom)
 *
 * \b Horizontal align (defaults to 'l' if no letter passed):
 *
 * - L -- the calendar is completely to the left of the element (right to left)
 * - l -- the calendar is to the left of the element but might overlap it (right to right)
 * - C -- the calendar is horizontally centered to the element
 * - r -- the calendar is to the right of the element but might overlap it (left to left)
 * - R -- the calendar is completely to the right of the element (left to right)
 *
 * @param el [HTMLElement] the anchor element
 * @param opts [string, optional] the align options, as described above.  Defaults to "Bl" if nothing passed.
 */
Zapatec.Window.prototype.showAtElement = function (el, opts) {
	if (!this.winDiv) {
		return false;
	}
	var self = this;
	var p = Zapatec.Utils.getAbsolutePos(el);
	if (!opts || typeof opts != "string") {
		this.showAt(p.x, p.y + el.offsetHeight);
		return true;
	}
	this.winDiv.style.display = "block";
	var w = self.winDiv.offsetWidth;
	var h = self.winDiv.offsetHeight;
	self.winDiv.style.display = "none";
	var valign = opts.substr(0, 1);
	var halign = "l";
	if (opts.length > 1) {
		halign = opts.substr(1, 1);
	}
	// vertical alignment
	switch (valign) {
	    case "T": p.y -= h; break;
	    case "B": p.y += el.offsetHeight; break;
	    case "C": p.y += (el.offsetHeight - h) / 2; break;
	    case "t": p.y += el.offsetHeight - h; break;
	    case "b": break; // already there
	}
	// horizontal alignment
	switch (halign) {
	    case "L": p.x -= w; break;
	    case "R": p.x += el.offsetWidth; break;
	    case "C": p.x += (el.offsetWidth - w) / 2; break;
	    case "l": p.x += el.offsetWidth - w; break;
	    case "r": break; // already there
	}
	p.width = w;
	p.height = h;
	Zapatec.Utils.fixBoxPosition(p);
	self.showAt(p.x, p.y);
	return true;
}

/**
 * Shows the calendar at a given absolute position (beware that, depending on
 * the calendar element style -- position property -- this might be relative to
 * the parent's containing rectangle).
 *
 * @param x [int] the X position
 * @param y [int] the Y position
 */
Zapatec.Window.prototype.showAt = function (x, y) {
	if (!this.winDiv) {
		return false;
	}
	this.setPos(x, y);
	this.show();
	return true;
}


