//*******************************************************************************
//
// File    : webwim.js
// Purpose : Provide an web based window management sytem as development frame 
//			 work for web base applications using DHTML and Ajax
//
// Version        Date         Comments
// ------------   ----------   --------------------------------------------------
// V1.0.DDS.0.0   02/19/2006   - Written.
// V1.1.DDS.0.0   02/20/2006   - Various name changes (menu->window, application->desktop).
//							   - Added onMouseDown=move for window title
// V1.2.DDS.0.0   02/22/2006   - Seperated the window content and added status bar.
// V1.3.DDS.0.0   02/23/2006   - Added doubleClick to title (fullscreen), collapse and minimize
// V1.4.DDS.0.0   02/24/2006   - Added focus on the currently selected window (z-index)
//								 Added window list
// V1.5.DDS.0.0   02/25/2006   - Added switch 'ajax' vs 'iframe' and added layout options
// V1.6.DDS.0.0   02/26/2006   - Change the windowObj constructor added more window options
// V1.7.DDS.0.0   02/28/2006   - Added cookie to keep state of windows (size, position, mode)
// V1.7.DDS.1.0   03/03/2006   - Hacked fix for IE to show the windowList
// V1.7.DDS.2.0   03/04/2006   - Split window settings in one cookie per window
// V1.8.DDS.0.0   03/05/2006   - Added resize from window borders
// V1.9.DDS.0.0   03/07/2006   - Set boxObj 'inner' attributes and use them
// V1.9.DDS.1.0   03/08/2006   - Implemented missing Window Settings
// V2.0.DDS.0.0   03/12/2006   - Implemented Tab Settings
// V2.0.DDS.1.0   03/12/2006   '->  Fixed bug with IE 
// V2.1.DDS.0.0   03/14/2006   - Improved resize functionality
// V2.2.DDS.0.0   03/16/2006   - Improved layout and minimize/close functionality
// V2.2.DDS.1.0   03/17/2006   '->  Fixed bug with IE 
// 
// Copyright & Author:	Daniel Schimpfoessl
// 
// Todo List    Fixed, Description
// ----------   -----------------------------------------------------------------
// 03/17/2006	-- Bug: Window content gets reset on resize 
// 03/05/2006	OK Bug: Window border and status are not at the right position
// 02/26/2006	OK Bug: IE does not show the windowList
//				-- Bug:	Mouse move is distracted over other windows (iframes)
//				OK Add:	Resize from window borders
// 02/19/2006	OK Bug: When detach is called on mouse down it sets detachedWindow 
//						and detachAction but does not release them on mouse up.
//				OK Add:	The boxObj "inner" attributes need to be set propper
//				OK Add:	Seperate window innerHTML into header, content, footer and
//						create functions to set them individually or all together
//				OK Add: Focus on the currently selected window (z-index)
//				-- Add: Only load content if window is open
//				O- Add: Save current webwim state using toString,... local
//						and remote (cookie, database)
//				OK		Still buggy
//*******************************************************************************

// SAMPLE USAGE
/*
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
<html>
	<head>
	<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
	
	<link rel="stylesheet" title="Default Style" href="/css/webwim.css" type="text/css">
	<script type="text/javascript"  src="/jskripte/webwim.js"></script>
	<title>webwim Framework Prototype</title>
	</head>
	<body>
		<div id="webwim-root"></div>
		<script language="JavaScript1.2">
			window_header_icon_path = "/images/webwim/";
			// desktop definition (posX, posY, grid_size, gridx, gridy, div_tag_name, root_div_tag_name)
			var desktop = new desktopObj(10, 10, 25, 40, 32, 'webwim-area', 'webwim-root');
			
			//function addNewWindow([id/name, posx,posy,width,height,state],	// windowAttributes
			//	[alwaysOnTop,collapseable,minimizeable,maximizeable,moveable,resizable,closeable,reloadable] //window settings
			//	[visible,title,icon],				// headerAttributes
			//	[visible,name,src,type,scrollable], // bodyAttributes
			//	[visible]							// footerAttributes
			//	[visible]							// tabAttributes
			//);
			desktop.addNewWindow(['empty',    125,  10, 450,  200, 'col'], [0, 1, 1, 1, 1, 1, 0, 1], [1, 'Empty',   ''], [1, '', 'empty.html'   , 'iframe'],[1],[1]);
			desktop.addNewWindow(['welcome',  125,  40, 450,  250, ''   ], [0, 0, 0, 0, 0, 0, 1, 1], [1, 'Welcome', ''], [1, '', 'file.html'    , 'ajax', ],[0],[0]);
			desktop.addNewWindow(['download',  10, 250, 400,  250, 'min'], [0, 1, 1, 1, 1, 1, 0, 1], [1, 'Download',''], [1, '', 'download.html', 'ajax'  ],[1],[1]);
			desktop.addNewWindow(['history',  300, 270, 400,  230, 'min'], [0, 1, 1, 1, 1, 1, 0, 1], [1, 'History', ''], [1, '', 'history.html' , 'iframe'],[1],[1]);
		</script>
	</body>
</html>
*/

// include other JS code not working for IE yet
var included_files = new Array();
//include_once('/jskripte/webwim.include/test.js');

// global event registry
document.onmousedown = setXY; // NS
document.onmousemove = handleWindowMove;

// global variables
var undef = -1;
var clickPosX, clickPosY;
var window_header_icon_path = "/images/webwim/";
// desktop definition (posX, posY, grid_size, gridx, gridy, div_tag_name, root_div_tag_name)
var desktop = '';
	
// detached window attributes
var detachedWindow  = null;
var detachedWindowX = 0;
var detachedWindowY = 0;
var detachedWindowW = 0;
var detachedWindowH = 0;
var detachAction = '';

function handleWindowMove(event){
  	if (!event)
    	event = window.event;
    if (detachedWindow != null && event.button){
    	var move = 0; var resize = 0;
		var myWindowObj = desktop.getWindow(detachedWindow.id);
    	var mousePosX = (event.pageX ? event.pageX : event.clientX);
    	var mousePosY = (event.pageY ? event.pageY : event.clientY);

		if (myWindowObj.parent.innerPosY > mousePosY) return;
		if (myWindowObj.parent.innerPosX > mousePosX) return;
    	
    	var mouseDeltaX = mousePosX - clickPosX;
    	var mouseDeltaY = mousePosY - clickPosY;
		var newX      = detachedWindowX + mouseDeltaX;
		var newY      = detachedWindowY + mouseDeltaY;
		var newWidth  = mousePosX - myWindowObj.posX - myWindowObj.parent.innerPosX;
		var newHeight = mousePosY - myWindowObj.posY - myWindowObj.parent.innerPosY;
    	
    	var pos = detachAction.split('-')[0] == 'resize' ? detachAction.split('-')[1] : '';
		if      (detachAction == "move")       move   = 1;
		else if (pos == "se")  resize = 1;
		else if (pos == "e" ){ newHeight = null; resize = 1;}
		else if (pos == "s" ){ newWidth  = null; resize = 1;}
		else if (pos == 'w' || pos == 'sw' || pos == 'n' || pos == 'ne' || pos == 'nw') {
			if (pos == 'w') newHeight = null; 
			if (pos == 'n') newWidth  = null;
			if (pos == 'w' || pos == 'sw') newY = null;
			if (pos == 'n' || pos == 'ne') newX = null;
			if (pos == 'w' || pos == 'sw' || pos == 'nw') newWidth  = detachedWindowW - mouseDeltaX;
			if (pos == 'n' || pos == 'ne' || pos == 'nw') newHeight = detachedWindowH - mouseDeltaY;
			resize = move = 1;
		}
		if (resize) myWindowObj.resize(newWidth, newHeight);
		if (move)   myWindowObj.move(newX, newY);
		return false;
	}
}
function detachWindow (window_id, action){
	// set and reset detachedWindow
	detachedWindow = null;
	detachAction = action;
	if (detachedWindow != desktop.getWindow(window_id))
		detachedWindow = desktop.getWindow(window_id);
	
	if (detachedWindow != null){
		var myWindowObj = detachedWindow;
		// switch window to wire mode to speed up rendering
		if (detachAction.split('-')[0] == 'resize') myWindowObj.setDisplayMode('resize');
		desktop.windowList.activateWindow(detachedWindow.id);
		detachedWindowX = myWindowObj.posX;
		detachedWindowY = myWindowObj.posY;
		detachedWindowW = myWindowObj.width;
		detachedWindowH = myWindowObj.height;
		if (document.all) setXY(event); // IE
		document.onmouseup = windowChanged;
	}
}
function windowChanged () {
	var myWindowObj = detachedWindow;
	if (myWindowObj != null){
		desktop.windowList.saveWindowAttributes(myWindowObj.id);
		// switch window to normal mode show the full window
		myWindowObj.setDisplayMode('normal');
	}
	detachedWindow = null;
	detachAction   = '';
}
function setXY (event){
  	if (!event)
    	event = window.event;
	clickPosX = (event.pageX ? event.pageX : event.clientX);
	clickPosY = (event.pageY ? event.pageY : event.clientY);
}
function adjustWindow (window_id, action) {
	var myWindowObj = desktop.getWindow(window_id);
	if (myWindowObj && action != null){
		if((action == 'close' || action == 'minimize') && !myWindowObj.minimized){
			myWindowObj.setState(action);
			desktop.windowList.deActivateWindow(window_id);
		}
		else { 
			if(myWindowObj.minimized || myWindowObj.collapsed || myWindowObj.maximized || myWindowObj.closed)
				myWindowObj.setState('restore');
			else if (action == 'maximize')
				myWindowObj.setState(action);
			else if (action == 'collapse')
				myWindowObj.setState(action);
			desktop.windowList.activateWindow(window_id);
		}
		desktop.windowList.saveWindowAttributes(window_id);
	}
}

// create the root class area
function desktopObj (posX, posY, grid_size, grid_x, grid_y, id, root_div_tag_id) {
	// initialize properties
	var parentRoot_div_tag = document.getElementById(root_div_tag_id);
	var self = new boxObj(id, parentRoot_div_tag);
	self.grid_size = grid_size;
	self.grid_x	   = grid_x;
	self.grid_y    = grid_y;
		
	// add properties
	self.parentRoot_div_tag = parentRoot_div_tag;

	// methods
	self.init          = init;
	self.addNewWindow  = addNewWindow;
	self.getWindow     = getWindow;
	self.log		   = log;
	
	// todo overwrite setSize, setInnerDimension	
	function init (posX, posY, width, height){
		var area = this.root_div_tag;
		this.setPosition (posX, posY);
		this.setSize (width, height);
		this.setInnerPosition(0, 0);
		this.setInnerSize(width - 2, height - 2);
		this.windowList = new windowListObj('window-list',this.posX,this.height + this.posY,this.width,25,this.parentRoot_div_tag);
		this.windowList.logWindow = this.addNewWindow(['log',  150, 100, 400,  200, 'nil'], [0, 0, 0, 0, 0, 0, 1, 1], [1, 'Log', '', 1], [0, '', '' , 'ajax'],[0],[1]);
		this.windowList.logWindow.resetWindowContent('no log entry<br>',0);
		
		area.style.background   =        '#efefef';
		area.style.border		= '1px solid #aaa';
		area.style.overflow		=         "hidden";
		return this;
	}
	//function addNewWindow(id/name, posx,posy,width,height,state,	// windowAttributes
	//	[alwaysOnTop,collapseable,minimizeable,maximizeable,moveable,resizable,closeable,reloadable] //window settings
	//	[visible,title,icon],				// headerAttributes
	//	[visible,name,src,type,scrollable], // bodyAttributes
	//	[visible]							// footerAttributes
	//	[visible]							// tabAttributes
	//	parent								// reference to parent object								
	//);
	function addNewWindow (windowAttributes, windowSettings, headerAttributes, bodyAttributes, footerAttributes, tabAttributes){
		return this.windowList.addWindow(new windowObj(windowAttributes, windowSettings, headerAttributes, bodyAttributes, footerAttributes, tabAttributes, this));
	}
	// returns the window object
	function getWindow (id){
		return this.windowList.getWindow(id);
	}
	// log 
	function log (message){
		var currentLog = this.windowList.logWindow.body.innerHTML;
		this.windowList.logWindow.resetWindowContent('<pre>' + message + '</pre><hr>' + currentLog, 0);
		this.windowList.logWindow.closed = false;
		this.windowList.initWindowList();
	}
	return self.init(posX,posY,grid_size*grid_x+2, grid_size*grid_y+2);	
}

// create the windowList class
function windowListObj (id, posX, posY, width, height, parentRoot_div_tag) {
	// create object from super object
	var self    = new boxObj(id, parentRoot_div_tag);
	self.parentRoot_div_tag = parentRoot_div_tag;

	// add properties
	self.windows           = new Array();
	self.windowsAttributes = new Array();
	self.windowCnt    = 0;
	self.activeWindow = '';

	// methods
	self.init      = init;
	self.addWindow = addWindow;
	self.delWindow = delWindow;
	self.getWindow = getWindow;
	self.initWindowList = initWindowList;
	self.activateWindow = activateWindow;
	self.deActivateWindow = deActivateWindow;
	self.saveWindowAttributes = saveWindowAttributes;
	self.loadWindowAttributes = loadWindowAttributes;
	
	// todo overwrite setSize, setInnerDimension	
	function init (posX, posY, width, height){
		var area = this.root_div_tag;
		this.setPosition (posX, posY);
		this.setSize (width, height);
		this.setInnerPosition(0, 0);
		this.setInnerSize(width - 2, height - 2);

		area.style.background   =        '#efefef';
		area.style.border		= '1px solid #aaa';
		area.style.overflow		=        "visible";
			
		return this;
	}
	// add windowObj to list
	function addWindow (myWindow){
		this.windows[myWindow.id] = new Array();
		this.windows[myWindow.id].obj = myWindow;
		this.windows[myWindow.id].pos = this.windowCnt++;
		// restore the window attributes if saved or activate window
		this.loadWindowAttributes(myWindow.id) ||
		this.activateWindow(myWindow.id, 1);
		this.initWindowList();
		return myWindow;
	}
	// return windowObj
	function getWindow (id){
		return this.windows[id].obj;
	}
	// remove windowObj from list
	function delWindow (id){
		this.windowCnt--;
		this.deActivateWindow(id);
		this.windows.splice(id,1);
		this.initWindowList();
	}
	// initWindowList
	function initWindowList (){
		var area = this.root_div_tag;
		if (document.all) { // IE hack
			var ieTable = '<table height="18px" cellpadding="3" cellspacing="1"><tr>';
			for (var window_id in this.windows){
				if (this.windows[window_id].obj.hasWindowTab() == 1){
					ieTable += '<td width="100px">' + this.windows[window_id].obj.getWindowTab() + '</td>';
				}
			}
			ieTable += "</tr></table>";
			area.innerHTML = ieTable;
		}
		else {
			while (area.firstChild) area.removeChild(area.firstChild);
			var table = document.createElement('table');
			    table.setAttribute("height", "18px");
			    table.setAttribute("cellpadding", 3);
			    table.setAttribute("cellspacing", 1);
			var row   = document.createElement('tr');
			for (var window_id in this.windows){
				if (this.windows[window_id].obj.hasWindowTab() == 1){
					var cell  = document.createElement('td');
				    	cell.setAttribute("width",  "100");
						cell.appendChild(this.windows[window_id].obj.getWindowTab());
					row.appendChild(cell);
				}
			}
			table.appendChild(row);
			area.appendChild(table);
		}
	}
	// activate window
	function activateWindow (id, init) {
		// only activate if inactive
		if (!this.windows[id].obj.activated){
//			desktop.log('activate ' + id);
			var oldPos = this.windows[id].pos;
			this.windows[id].pos = this.windowCnt; // top layer
			
			var oldActiveWindow_id = 0;
			// shift other windows down
			for(window_id in this.windows){
				// set active to false for all windows
				this.windows[window_id].obj.activate(false);
				// is this window blocking me (pos > myPos)
				if (window_id != id && this.windows[window_id].pos > oldPos){
					// deactivate window
					this.windows[window_id].pos--;
					// capture the window status
					if(!init) this.saveWindowAttributes(window_id);
//					desktop.log(this.windows[window_id].obj.root_div_tag.style.zIndex);
				}
				this.windows[window_id].obj.root_div_tag.style.zIndex = this.windows[window_id].pos * 10;
			}
			// set current window to active
			this.activeWindow = id;
			this.windows[id].obj.activate(true);
			this.initWindowList();
			if(!init) this.saveWindowAttributes(id);
		}
	}
	// deActivate window
	function deActivateWindow (id) {
		if (this.windows[id].obj.activated){
//			desktop.log('deActivate ' + id);
			var oldPos = this.windows[id].pos;
			this.windows[id].obj.activate(false);
	
			var winPos = new Array();
			for(window_id in this.windows) winPos[this.windows[window_id].pos] = window_id;
				
			// activate the next window in the row
			for(pos in winPos.sort()){
				var window_id = winPos[pos];
//				desktop.log('check' + window_id);
				if (window_id != id && !this.windows[window_id].obj.minimized){
//					desktop.log('take' + window_id);
					this.activateWindow(window_id);
					return;
				}
			}
		}
	}
	// save window attributes
	function saveWindowAttributes (id) {
		var attributes = this.windows[id].obj.getWindowAttributes();
		var windowAttr = new Array; 
		for(var attribute in attributes) windowAttr[windowAttr.length] =  attribute + '=' + attributes[attribute];
		this.windows[id].attrStrg = windowAttr.join('|');
		setCookie('webwim.window.' + id + '.attributes', this.windows[id].attrStrg);
	}
	// restore all window attributes
	function loadWindowAttributes (id) {
		// for the cookie
		var cookieStrg = getCookie('webwim.window.' + id + '.attributes') || '';
		try {
			this.windows[id].attrStrg = cookieStrg;
			var attributes = new Array();
			var windowAttr = cookieStrg.split('|');
			for(var attribute in windowAttr){
				var elem = windowAttr[attribute].split('=');
				attributes[elem[0]] = elem[1];
			}
			if (id != 'log' && attributes.id != null)
				return this.windows[id].obj.restoreWindowAttributes(attributes);
			return 0;
		}
		catch (e){
			if(desktop) desktop.log(e.toString()); else alert(e.toString());
		}
	}
	return self.init(posX, posY, width, height);
}

// create the application class
function applicationObj (id, title, URL, parent) {
	// create object from super object
	// add properties
	// methods
	self.init          = init;
	
	// init the object
	function init (){
		return this;
	}
	return self.init();
}

// create the window class
	//function addNewWindow(id/name, posx,posy,width,height,state,	// windowAttributes
	//	[alwaysOnTop,collapseable,minimizeable,maximizeable,moveable,resizable,closeable,reloadable] //window settings
	//	[visible,title,icon],				// headerAttributes
	//	[visible,name,src,type,scrollable],	// bodyAttributes
	//	[visible]							// footerAttributes
	//	[visible]							// tabAttributes
	//	parent								// reference to parent object								
	//);
function windowObj (windowAttributes, windowSettings, headerAttributes, bodyAttributes, footerAttributes, tabAttributes, parent){
	// extract attributes for initiation use
	// window 
	var id	     = windowAttributes[0];
	var posX	 = windowAttributes[1];          
	var posY	 = windowAttributes[2];
	var width	 = windowAttributes[3];
	var height	 = windowAttributes[4];
	var state    = windowAttributes[5];
	
	// create object from super object
	var self        = new boxObj(windowAttributes[0], parent.root_div_tag);

	// initialize properties
	self.parent = parent;					// reference to parent object
	self.title  = headerAttributes[1];		// header/tab title
	self.icon   = headerAttributes[2] || 'webwim.gif';
	self.name       = bodyAttributes[1];		// iframe name
	self.URL        = bodyAttributes[2];		// content source
	self.type       = bodyAttributes[3];		// content type (iframe or ajax)
	self.scrollable = bodyAttributes[4] || 0;   // show scrollbars for body?
	self.headerOn = headerAttributes[0];	// show window header
	self.bodyOn   = bodyAttributes[0];	    // load window content
	self.footerOn = footerAttributes[0];	// show window footer
	self.tabOn	  = tabAttributes[0];		// show window tab in window list
	self.onTopOn      = windowSettings[0] || 0;  // keep on top at all times
	self.collapseable = windowSettings[1] || 0;
	self.minimizeable = windowSettings[2] || 0;
	self.maximizeable = windowSettings[3] || 0;
	self.moveable     = windowSettings[4] || 0;
	self.resizable    = windowSettings[5] || 0;
	self.closeable    = windowSettings[6] || 0;
	self.reloadable   = windowSettings[7] || 0;
	
	// add properties
	self.maximized = false;
	self.minimized = false;
	self.collapsed = false;
	self.activated = false;
	self.closed    = false;
	
	self.useGrid   = 1;	   
	
	// methods
	self.init   = init;
	self.move   = move;
	self.resize = resize;
	self.collapse = collapse;
	self.minimize = minimize;
	self.restore  = restore;
	self.maximize = maximize;
	self.close    = close;
	self.activate = activate;
	self.setState = setState;
	self.setWindowResize  = setWindowResize;	// creates a one pixel border for resizing
	self.setWindowHeader  = setWindowHeader;
	self.setWindowFooter  = setWindowFooter;
	self.setWindowContent = setWindowContent;
	self.setWindowTab     = setWindowTab;
	self.getWindowTab     = getWindowTab;
	self.hasWindowTab     = hasWindowTab;
	self.setDisplayMode   = setDisplayMode;
	self.resizeWindowContent = resizeWindowContent;
	self.initWindowContent   = initWindowContent;
	self.resetWindowContent  = resetWindowContent;
	self.resetWindowStatus   = resetWindowStatus;
	self.getWindowAttributes = getWindowAttributes;
	self.restoreWindowAttributes = restoreWindowAttributes;
	
	function init (posX, posY, width, height, state){
		var area  = this.root_div_tag;
		addEvent(area, 'click', function(){desktop.windowList.activateWindow(this.id);});
		area.style.background   =        '#ffffff';
		area.style.border		= '1px solid #000';
		area.style.overflow		=         "hidden";

		this.headerHeight = 17;
		this.footerHeight = this.headerHeight;
		this.move(posX, posY);
		this.resize(width, height);
		
		// initiate content retrieval
		this.setWindowResize();	// creates the resize border around the window
		this.setWindowHeader(this.title, this.icon);
		this.setWindowFooter('Status');
		this.setWindowContent(this.URL, 1);
		this.resetWindowStatus('Done');

		// restore/set state
		this.setState(state);
				
		return this;
	}
	function setDisplayMode (mode) {
		var area  = this.root_div_tag;
		if (mode == 'normal'){
			this.useGrid = 1;
			this.resizing = 0;
			area.style.opacity		  = 1.0;
			area.style.filter         = 'alpha(opacity=100)';
			this.body.style.display   = 'block';
			this.footer.style.display = 'block';
			this.move   (this.posX,this.posY);
			this.resize (this.width,this.height);
		}	
		else if (mode == 'resize'){
			this.useGrid = 0;
			this.resizing = 1;
			area.style.opacity		  = '0.6';
			area.style.filter         = 'alpha(opacity=60)';
			this.body.style.display   = 'none';
			this.footer.style.display = 'none';
		}	
	}
	function move (posX, posY){
		var grid_size = this.parent.grid_size;   
		var grid_x	  = this.parent.grid_x;
		var grid_y    = this.parent.grid_y;
		
		if (posX == null || posX < 0) posX = this.posX;   
		if (posY == null || posY < 0) posY = this.posY;   

		// verify that the new position is within the grid boundary
		if (this.width  + posX > grid_size * grid_x) posX = grid_size * grid_x - this.width;  if (posX < 0) posX = 0;
		if (this.height + posY > grid_size * grid_y) posY = grid_size * grid_y - this.height; if (posY < 0) posY = 0;

		if (this.useGrid){
			// find the closest grid point
			posX = Math.floor((posX - (grid_size / 2)) / grid_size + 1) * grid_size;
			posY = Math.floor((posY - (grid_size / 2)) / grid_size + 1) * grid_size;
		}

		this.setPosition (posX, posY);
	}
	function resize (width, height){
		var grid_size = this.parent.grid_size;   
		var grid_x	  = this.parent.grid_x;
		var grid_y    = this.parent.grid_y;
		
		if (height == null || height < 0) height = this.height;   
		if (width  == null || width  < 0) width  = this.width;   
		
		// make sure, that the window controlls are still accessible
		var minHeight = this.collapsed ? this.headerHeight : this.headerHeight + this.footerHeight;
		if (width  < 95       ) width  = 95;
		if (height < minHeight) height = minHeight;
		// verify that the new position is within the grid boundary
		if (width  + this.posX > grid_size * grid_x) width  = grid_size * grid_x - this.posX; if (width  < grid_size) width  = grid_size;
		if (height + this.posY > grid_size * grid_y) height = grid_size * grid_y - this.posY; if (height < grid_size) height = grid_size;

		if (this.useGrid){
			// find the closest grid point
			width  = Math.ceil(width  / grid_size) * grid_size;
			height = Math.ceil(height / grid_size) * grid_size;
		}

		this.setSize (width, height);
		if (!this.resizing){
			this.setInnerSize(width - 2, height - this.headerOn * this.headerHeight - this.footerOn * this.footerHeight);
			this.setWindowResize();
	//		this.initWindowContent();
			this.resizeWindowContent();
		}
	}
	function activate (bool) {
		this.activated = bool == true ? true : false;
		var attributeName = document.all ? 'className' : 'class'; // IE vs NS
		var windowHeaderCssClass = 'window-header' + (this.activated ? '-active' : '');
		var windowFooterCssClass = 'window-footer' + (this.activated ? '-active' : '');
		this.header.firstChild.setAttribute(attributeName, windowHeaderCssClass);
		this.footer.firstChild.setAttribute(attributeName, windowFooterCssClass);
		this.setWindowTab(this.title);
	}
	function collapse () {
		if (!self.collapseable) return;
		this.collapsed = true;
		this.maximized = false;
		this.minimized = false;
		this.restoreToHeight = this.height;
		this.restoreToWidth  = this.width;
		this.resize(this.width, 1);
	}
	function minimize () {
		if (!self.minimizeable) return;
		this.minimized = true;
		this.root_div_tag.style.display = 'none';
	}
	function maximize () {
		if (!self.maximizeable) return;
//		desktop.log(this.parent.innerWidth + ', ' + this.parent.innerHeight);
		this.minimized = false;
		this.collapsed = false;
		this.maximized = true;
//		this.root_div_tag.style['z-index'] = 10;
		this.restoreToHeight = this.height;
		this.restoreToWidth  = this.width;
		this.restoreToPosX   = this.posX;
		this.restoreToPosY   = this.posY;
		this.move(0, 0);
		this.resize(this.parent.innerWidth, this.parent.innerHeight, 'maximize');
	}
	function close () {
		if (!self.closeable) return;
		this.closed = true;
		this.root_div_tag.style.display = 'none';
	}
	function restore () {
//		desktop.log(this.restoreToPosX + ', ' + this.restoreToPosY + ', ' + this.restoreToWidth + ', ' + this.restoreToHeight);
		var maximized = this.maximized;
		if (this.minimized || this.closed){
			this.minimized = false;
			this.closed    = false;
			this.root_div_tag.style.display = 'block'; // from minimized
			return;
		}
		this.collapsed = false;
		this.maximized = false;
		this.resize(this.restoreToWidth, this.restoreToHeight, 'restore'); // from colapsed + x
		if (maximized)
			this.move(this.restoreToPosX, this.restoreToPosY, 'restore'); // from maximized + x
		this.restoreToHeight = this.height;
		this.restoreToWidth  = this.width;
		this.restoreToPosX   = this.posX;
		this.restoreToPosY   = this.posY;
	}
	// resize area around the window
	function setWindowResize (){
		var div = document.createElement('div');
		if (this.resizable && !this.collapsed){
			var window_id = this.root_div_tag.id;
			var borderDef = new Array();
			var cs = 4; // corner size
			var bs = 2; // border size
			var w = this.width;
			var h = this.height;
			var xc  = w - cs;
			var xb  = w - bs;
			var x2c = w - 2 * cs;
			var yc  = h - cs;
			var yb  = h - bs;
			var y2c = h - 2 * cs;
			borderDef['w']  = [  0, cs,  bs, y2c, 'x' ]; 
			borderDef['nw'] = [  0,  0,  cs,  cs, 'xy']; 
			borderDef['n']  = [ cs,  0, x2c,  bs, 'y' ]; 
			borderDef['ne'] = [ xc,  0,  cs,  cs, 'yx']; 
			borderDef['e']  = [ xb, cs,  bs, y2c, 'x' ]; 
			borderDef['se'] = [ xc, yc,  cs,  cs, 'xy']; 
			borderDef['s']  = [ cs, yb, x2c,  bs, 'y' ]; 
			borderDef['sw'] = [  0, yc,  cs,  cs, 'yx'];
			var divTags = '';
			for (var pos in borderDef){
				divTags += '<div id="'+window_id+'-resize-border-'+pos+'"  class="window-option-resize-'+borderDef[pos][4]+'"   style="left:'+borderDef[pos][0]+'px;top:'+borderDef[pos][1]+'px;width:'+borderDef[pos][2]+'px;height:'+borderDef[pos][3]+'px" onMouseDown="detachWindow(\''+window_id+'\', \'resize-'+pos+'\' )"></div>';
			}
			div.innerHTML = divTags;
		}
		return this.resizeFrame = div;
	}
	// window header
	function setWindowHeader (title, icon) {
		this.title = title;
		var optionWidth = (this.reloadable + this.minimizeable + this.collapseable + this.maximizeable + this.closeable) * 15;
		var window_id = this.root_div_tag.id;
		var header  = '<table width="100%" height="100%" class="window-header" cellpadding="0" cellspacing="1">';
		    header += '  <tr>'; 
		    header += '    <td width="15" align="left">';
		    header +=         '<img class="window-option-move"     title="move"     width="14" height="14" src="'+window_header_icon_path+icon+'"  ondblclick="adjustWindow(\''+window_id+'\', \'minimize\')" onMouseDown="detachWindow(\''+window_id+'\', \'move\')"/>'; 
		    header +=     '</td>'; 
		    header += '    <th><div style="width:100%" ondblclick="adjustWindow(\''+window_id+'\', \'maximize\')" onMouseDown="detachWindow(\''+window_id+'\', \'move\')">';
		    header +=     	title; 
		    header +=     '</div></td>'; 
		    header += '    <td align="right" width="' + optionWidth + 'px">';
		    if (this.reloadable)
		    header +=         '<img class="window-option-reload"   title="reload"   width="14" height="14" src="'+window_header_icon_path+'reload.gif"   onClick="desktop.getWindow(\''+window_id+'\').resetWindowContent(\''+this.URL+'\', 1)"/>'; 
		    if (this.minimizeable)
		    header +=         '<img class="window-option-minimize" title="minimize" width="14" height="14" src="'+window_header_icon_path+'minimize.gif" onClick="adjustWindow(\''+window_id+'\', \'minimize\')"/>'; 
		    if (this.collapseable)
		    header +=         '<img class="window-option-collapse" title="collapse" width="14" height="14" src="'+window_header_icon_path+'collapse.gif" onClick="adjustWindow(\''+window_id+'\', \'collapse\')"/>'; 
		    if (this.maximizeable)
		    header +=         '<img class="window-option-maximize" title="maximize" width="14" height="14" src="'+window_header_icon_path+'maximize.gif" onClick="adjustWindow(\''+window_id+'\', \'maximize\')"/>'; 
		    if (this.closeable)
		    header +=         '<img class="window-option-close"    title="close"    width="14" height="14" src="'+window_header_icon_path+'close.gif"    onClick="adjustWindow(\''+window_id+'\', \'close\')"   />';   
		    header +=     '</td>'; 
		    header += '  </tr>'; 
		    header += '</table>'; 
		var div = document.createElement('div');
		div.style.height = this.headerHeight + "px";
		div.innerHTML = header;
		this.setWindowTab(title);
		return this.header = div;
	}	
	// window footer
	function setWindowFooter (status){
		this.status = status;
		var window_id = this.root_div_tag.id;
		var footer  = '<table width="100%" height="100%" class="window-footer" cellpadding="0" cellspacing="1">';
		    footer += '  <tr>'; 
		    footer += '    <td align="left">';
		    footer +=     	status; 
		    footer +=     '</td>'; 
		    footer += '    <td align="right" width="16px">';
		    if (!this.maximized && this.resizable)
			footer += 	 	'<img class="window-option-resize" title="resize"    width="14" height="14" src="'+window_header_icon_path+'/resize.gif"   onMouseDown="detachWindow(\''+window_id+'\', \'resize-se\')"/>'; 
		    footer +=     '</td>'; 
		    footer += '  </tr>'; 
		    footer += '</table>'; 
		var div = document.createElement('div');
		div.style.height = this.footerHeight + "px";
		div.innerHTML = footer;
		return this.footer = div;
	}
	// window icon
	function setWindowTab (iconTitle){
		var window_id = this.root_div_tag.id;
		if (document.all) { // IE hack
			return this.windowTab = '<table width="100px" height="16px" cellpadding="0" cellspacing="1"' + 
			       ' class="' + (this.activated ? "window-tab-active" : "window-tab") + '"' +
			       ' onClick="if (desktop.getWindow(\'' + window_id + '\').activated || desktop.getWindow(\'' + window_id + '\').minimized) ' +
				   ' adjustWindow(\'' + window_id + '\', \'minimize\'); else desktop.windowList.activateWindow(\'' + window_id + '\');">' +
				   ' <tr><td width="15px"><img src="'+ window_header_icon_path + this.icon +'"></td>' + 
				   ' <td>' + iconTitle + '</td></tr></table>';		
		}
		else {
			var icon = document.createElement('img');
			    icon.src = window_header_icon_path + this.icon;
			    icon.style.width  = "14px";
			    icon.style.height = "14px";
			var table = document.createElement('table');
			    table.setAttribute("width",  "100px");
			    table.setAttribute("height", "16px");
			    table.setAttribute("cellpadding", 0);
			    table.setAttribute("cellspacing", 1);
			    table.setAttribute("class", this.activated ? "window-tab-active" : "window-tab");
			    table.id = this.id + "-window-tab";
				addEvent(table, 'click', function(){
					if (desktop.getWindow(window_id).activated || 
						desktop.getWindow(window_id).minimized)
						adjustWindow(window_id, 'minimize');
					else 
						desktop.windowList.activateWindow(window_id);
				});
			var row   = document.createElement('tr');
			var cell  = document.createElement('td');
			    cell.setAttribute("width", "15px");
			    cell.appendChild(icon); 
			row.appendChild(cell);
			var cell  = document.createElement('td');
				cell.appendChild(document.createTextNode(iconTitle));
			row.appendChild(cell);
			table.appendChild(row);
			return this.windowTab = table;
		}
	}
	// window icon
	function getWindowTab (){
		return this.windowTab;
	}
	function hasWindowTab (){
		return ((self.tabOn || this.minimized) && !this.closed ? 1 : 0);
	}
	// window content
	function setWindowContent (content, asUrl){
		if (asUrl == 1) this.URL  = content;
		if(this.type == "ajax"){ // AJAX
			var div = document.createElement('div');
			    div.id = this.id + "-content";
				div.style.width  = "100%";
				div.style.height = "100%";
				div.style.overflow = this.scrollable ? 'auto' : 'hidden';
			if (this.URL && asUrl){
				ajaxRequest(content, this.id);
				div.innerHTML = "Loading ...";
			}
			else {
				div.innerHTML = content;
			}
			this.body = div;
		}
		else { // IFRAME
			var iframe = document.createElement('iframe');  
			    iframe.setAttribute("name", this.name || this.id);
			    iframe.style.width  = "100%";
			    iframe.style.height = "100%";
			    iframe.style.border =  "0px";
			    iframe.setAttribute("scrolling", this.scrollable ? 'auto' : 'no');
			    iframe.setAttribute("frameborder", 0);
			if (this.URL && asUrl == 1)
			    iframe.setAttribute("src", this.URL);
			else 
				iframe.innerHTML = content;
			this.body = iframe;
		}
		return this.body;
	}
	// refresh windowContent
	function resetWindowContent (content, asUrl){
		this.setWindowContent(content, asUrl);
		this.initWindowContent();
	}
	// refresh windowStatus
	function resetWindowStatus (status){
		this.setWindowFooter (status);
		this.initWindowContent();
	}
	// initWindowContent
	function initWindowContent (){
		var area  = this.root_div_tag;
		try {
			resizeWindowContent();
			while (area != null && area.firstChild) area.removeChild(area.firstChild);
		} catch(e) {
			if (desktop) desktop.log('Could not remove window content for window ' + this.id + '\n' + e.toString())
		}
		try {
			var component = 'header';
 			if (this.headerOn   && this.header)     area.appendChild(this.header);		component = 'body';
			if (this.body                     )     area.appendChild(this.body);		component = 'footer';
			if (this.footerOn   && this.footer)     area.appendChild(this.footer);		component = 'resizeFrame';
			if (this.resizable  && this.resizeFrame)area.appendChild(this.resizeFrame); component = 'all';
		} catch(e) {
			if (desktop) desktop.log('Could not create window content "' + component + '" for window "' + this.id + '"\n' + e.toString())
		}
	}
	function resizeWindowContent () {
		if (this.body) this.body.style.height = this.innerHeight + "px";
	}
	// set window state
	function setState(state){
		state = state || '';
		if      (state == 'col'  || state == 'collapse') this.collapse();
		else if (state == 'max'  || state == 'maximize') this.maximize();
		else if (state == 'open' || state == 'restore' ) this.restore();
		else if (state == 'nil'  || state == 'close'   ) {
			state = this.state; 
			this.close();
		}
		else if (state == 'min' || state == 'minimize') {
			state = this.state; 
			this.minimize();
		}
		this.state = state; 
		return state;
	}
	// get window attributes
	function getWindowAttributes () {
		var attributes = this.getAttributes();
			attributes.restoreToHeight = this.maximized || this.collapsed ? this.restoreToHeight : this.height;
			attributes.restoreToWidth  = this.maximized || this.collapsed ? this.restoreToWidth  : this.width;
			attributes.restoreToPosX   = this.maximized || this.collapsed ? this.restoreToPosX   : this.posX;
			attributes.restoreToPosY   = this.maximized || this.collapsed ? this.restoreToPosY   : this.posY;
			attributes.minimized       = this.minimized == true ? 'true' : 'false';
			attributes.activated       = this.activated == true ? 'true' : 'false';
			attributes.closed          = this.closed    == true ? 'true' : 'false';
		    attributes.state           = this.maximized || this.collapsed ? this.state : 'open';
		    return attributes;
	}
	// get window attributes
	function restoreWindowAttributes (attributes) {
		this.height = parseInt(attributes.height || 0);  
		this.width  = parseInt(attributes.width  || 0);
		this.posX   = parseInt(attributes.posX   || 0);
		this.posY   = parseInt(attributes.posY   || 0);
		this.restoreToHeight = parseInt(attributes.restoreToHeight) || this.height;
		this.restoreToWidth  = parseInt(attributes.restoreToWidth)  || this.width ; 
		this.restoreToPosX   = parseInt(attributes.restoreToPosX)   || this.posX  ;  
		this.restoreToPosY   = parseInt(attributes.restoreToPosY)   || this.posY  ;  

		if (this.restoreToPosX != null && this.restoreToPosY != null ){
			this.move(this.restoreToPosX, this.restoreToPosY);
		}
		if (this.restoreToWidth != null && this.restoreToHeight != null ){
			this.resize(this.restoreToWidth, this.restoreToHeight);
		}
		this.setState(attributes.state);

		if     (attributes.minimized == 'true') this.setState('minimize');
		else if(attributes.closed    == 'true') this.setState('close');
		else if(attributes.maximized == 'true') this.setState('maximize');
		if     (attributes.activated == 'true') desktop.windowList.activateWindow(this.id);
		
		return 1;
	}
	return self.init(posX,posY,width,height,state);	
}
// create the box class
function boxObj (id, parentRoot_div_tag) {
	// initialize properties
	this.id         = id;
	this.parentRoot_div_tag = parentRoot_div_tag;  
	
	// add properties

	// methods
	this.init = init;
	this.getAttributes = getAttributes;
	// define the dimensions of this box
	this.setPosition = setPosition;
	this.setSize	 = setSize;
	// define the inner dimensions of this box
	this.setInnerPosition  = setInnerPosition;
	this.setInnerSize	   = setInnerSize;
	this.getInnerDimension = getInnerDimension;
	
	function setPosition (posX, posY) {
		var area  = this.root_div_tag;
		
		// set new position
		var position = 'relative'; 
		if (posX != null && posX >= 0){
			this.posX = posX
			area.style.left = posX + "px";
			position        =  "absolute";
		}
		if (posY != null && posY >= 0){
			this.posY = posY;
			area.style.top  = posY + "px";
			position        =  "absolute";
		}
		area.style.position = position;
	}	
	function setSize (width, height) {
		var area 	= this.root_div_tag;
		if (width != null && width >= 0){
			this.width  = width;
			area.style.width  = width + "px";
		}
		if (height != null && height >= 0){
			this.height = height;
			area.style.height = height + "px";	
		}	
	}	
	// sets the inner area position
	function setInnerPosition (posX, posY) {
		if (posX < 0) posX = 0;
		if (posY < 0) posY = 0;
		this.innerPosX   = posX;
		this.innerPosY   = posY;
	}	
	// sets the inner area dimensions
	function setInnerSize (width, height) {
		if (height < 0) height = 0;
		if (width  < 0) width  = 0;
		this.innerWidth  = width;
		this.innerHeight = height;
	}	
	// returns the usable area within this object
	function getInnerDimension (){
		return [this.innerPosX, this.innerPosY, this.innerWidth, this.innerHeight];	
	}
	// returns the boxObject attributes
	function getAttributes (){
		var attribute = new Array();
//		for(var attribute in this) if (this[attribute] != null) attributes[attribute] = this[attribute];
		    attribute.id          = this.id;
		    attribute.innerPosX   = this.innerPosX;
		    attribute.innerPosY   = this.innerPosY;
		    attribute.innerWidth  = this.innerWidth;
		    attribute.innerHeight = this.innerHeight;
		    attribute.posX   	  = this.posX;
		    attribute.posY   	  = this.posY;
		    attribute.width  	  = this.width;
		    attribute.height 	  = this.height;
		return attribute;
	}	
	// returns the boxObject as string
	function toString (){
		return "boxObj:: position:" + this.posX + ", " + this.posY + " size:" + this.width + " x " + this.height;
	}
	// create new box object and attach it to its parent div tag
	function init (){
		var this_div = document.createElement('div'); 
		    this_div.id = this.id;
		this.parentRoot_div_tag.appendChild(this_div);
		this.root_div_tag = this_div;
		if (this.root_div_tag == null) {return desktop.log ("Could not create element root: " + this.id)};
		return this;
	}	
	return this.init();	
}

function ajaxRequest(url, window_id){
	var ajaxRequest = false
	if (window.XMLHttpRequest) // if Mozilla, Safari etc
		ajaxRequest = new XMLHttpRequest()
	else if (window.ActiveXObject){ // if IE
		try {
			ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP")
		} 
		catch (e){
		try{
			ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP")
		}
		catch (e){}
		}
	}
	else
		return false
	ajaxRequest.onreadystatechange = function(){updateWindow(ajaxRequest, window_id)}
	ajaxRequest.open('GET', url, true)
	ajaxRequest.send(null)
}

function updateWindow(ajaxRequest, window_id){
	if (ajaxRequest.readyState == 4 && (ajaxRequest.status == 200 || 
		window.location.href.indexOf("http") == -1))				// content, asUrl, rebound
		desktop.getWindow(window_id).resetWindowContent(ajaxRequest.responseText, 0, 1);
}

function getCookie (name) {  
	var arg = name + "=";  
	var alen = arg.length;  
	var clen = document.cookie.length;  
	var i = 0;  
	while (i < clen) {    
		var j = i + alen;    
		if (document.cookie.substring(i, j) == arg)      
			return getCookieVal (j);    
		i = document.cookie.indexOf(" ", i) + 1;    
		if (i == 0) break;   
	}  
	return null;
}
function getCookieVal(offset) {
   var endstr = document.cookie.indexOf (";", offset);
   if (endstr == -1) endstr = document.cookie.length;
   return unescape (document.cookie.substring(offset, endstr));
}
function setCookie (name, value) {  
	var argv = setCookie.arguments;  
	var argc = setCookie.arguments.length;
	var then = new Date();
	then.setTime(then.getTime() + 13000000);  // around 150 days
	var expires = (argc > 2) ? argv[2] : then;
	var path    = (argc > 3) ? argv[3] : null;  
	var domain  = (argc > 4) ? argv[4] : null;  
	var secure  = (argc > 5) ? argv[5] : false;
	
	document.cookie = name + "=" + escape (value) + 
		((expires == null) ? "" : ("; expires=" + expires.toGMTString())) + 
		((path    == null) ? "" : ("; path=" + path)) +  
		((domain  == null) ? "" : ("; domain=" + domain)) +    
		((secure  != true) ? "" :  "; secure");
}
function deleteCookie (name) {  
	var exp = new Date();  
	exp.setTime (exp.getTime() - 1);  
	var cval = getCookie (name);  
	document.cookie = name + "=" + cval + "; expires=" + exp.toGMTString();
}

function addEvent( obj, type, fn ) {
	try {
		if ( obj.attachEvent ) { 
			obj['e'+type+fn] = fn; 
			obj[type+fn] = function(){obj['e'+type+fn]( window.event );} 
			obj.attachEvent( 'on'+type, obj[type+fn] ); 
		} else 
			obj.addEventListener( type, fn, false );
		obj = null;
	}
	catch (e) {
			desktop.log('Could not add event '+ type +' for window ' + obj.id + '\n' + e.toString())
	}
} 
function removeEvent( obj, type, fn ) { 
	try {
		if ( obj.detachEvent ) { 
			obj.detachEvent( 'on'+type, obj[type+fn] ); 
			obj[type+fn] = null; 
		} else 
			obj.removeEventListener( type, fn, false ); 
		obj = null;
	}
	catch (e) {
			desktop.log('Could not remove event '+ type +' for window ' + obj.id + '\n' + e.toString())
	}
}

function include_once(script_filename) {
	if (included_files[script_filename] == null) {
		included_files[script_filename] = 1;
		include_dom(script_filename);
	}
}
function include_dom(fileName) {
	var html_doc = document.getElementsByTagName('head').item(0);
	fileType = fileName.substring(fileName.lastIndexOf('.') + 1);
	if (fileType == 'js'){
		var include = document.createElement('script');
		include.setAttribute('language','javascript');
		include.setAttribute('type','text/javascript');
		include.setAttribute('src',fileName);
	}
	else if (fileType=='css'){
		var include = document.createElement('link');
		include.setAttribute('rel','stylesheet');
		include.setAttribute('type','text/css');
		include.setAttribute('href',fileName);
	}
	html_doc.appendChild(include);
	return false;
}

