/* Copyright (c) 2008 Extentech Inc. All Rights Reserved

##### Sheetster&trade; Web Application #####

This file is a part of the Sheetster&trade; Web Application

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

If you would like to redistribute this software in a closed-source application,
dual-licensed commercial versions are available from Extentech.

For a fully supported and redistributable commercial license, 
please visit www.extentech.com or contact us at:

 sales@extentech.com
 Extentech Inc.
 1032 Irving Street #910
 San Francisco, CA 94122
 415-759-5292
 
*/
/*
Site-wide Javascript Utils

	Event Attaching		_/
	Windowing / Dialog
	Browser Detection 
	Element Addition  _/
	Element Position _/
	Debug/Logging
	Constants	

*/

/******* VARIABLES *********/

var gstrActiveLayer = ""
var is;


/**
 * http://www.shawnolson.net
 *
 * @param theClass
 * @param element
 * @param value
 * @return
 */
function changecss(theClass,element,value) {
	//Last Updated on June 23, 2009
	//documentation for this script at
	//http://www.shawnolson.net/a/503/altering-css-class-attributes-with-javascript.html
	 var cssRules;

	 var added = false;
	 for (var S = 0; S < document.styleSheets.length; S++){
		 if (document.styleSheets[S]['rules']) {
			 cssRules = 'rules';
		 }else if (document.styleSheets[S]['cssRules']) {
			 cssRules = 'cssRules';
		 } else {
			 //no rules found... browser unknown
		 }
		 for (var R = 0; R < document.styleSheets[S][cssRules].length; R++) {
			 if (document.styleSheets[S][cssRules][R].selectorText == theClass) {
				 if(document.styleSheets[S][cssRules][R].style[element]){
					 document.styleSheets[S][cssRules][R].style[element] = value;
					 added=true;
					 break;
				 }
			 }
		 }
		 if(!added){
		  	if(document.styleSheets[S].insertRule){
		  		document.styleSheets[S].insertRule(theClass+' { '+element+': '+value+'; }',document.styleSheets[S][cssRules].length);
		  	}else if (document.styleSheets[S].addRule) {
		  		document.styleSheets[S].addRule(theClass,element+': '+value+';');
		  	}
		 }
	 }
	}


/******* Browser detection *********/

/**
 * NOTE: if you add browser agents to the list do not forget to lowercase
 * the string!
 * 
 */
function Is (){
    
	var agt= window.navigator.userAgent.toLowerCase();
    
    this.major		= parseInt(navigator.appVersion);
    this.minor		= parseFloat(navigator.appVersion);
    
    this.nav		= ((agt.indexOf('mozilla')!=-1) && (agt.indexOf('spoofer')==-1) && (agt.indexOf('compatible') == -1) && (agt.indexOf('opera')==-1) && (agt.indexOf('webtv')==-1) && (agt.indexOf('hotjava')==-1));
    this.nav4		= (this.nav && (this.major == 4));
    this.nav6up		= (this.nav && (this.major >= 5));
    this.ie			= ((agt.indexOf("msie") != -1) && (agt.indexOf("opera") == -1));
    this.ie4		= (this.ie && (this.major == 4) && (agt.indexOf("msie 5")==-1) );
    this.ie4up		= (this.ie && (this.major >= 4));
    this.ie6down	= (this.ie && (this.major <= 6));    
    this.mac		= (agt.indexOf("mac")!=-1);
    this.iphone		= (agt.indexOf("iphone")!=-1);
	this.ipad		= (agt.indexOf("ipad")>-1);    
    this.ff			= (agt.indexOf("firefox")>-1);
    this.ff2		= (agt.indexOf("firefox/2.")>-1);
    this.ff3		= (agt.indexOf("firefox/3.")>-1);
    this.ff4		= (agt.indexOf("firefox/4.")>-1);     
    this.webkit		= (agt.indexOf("applewebkit")>-1);
    
    // iphone and ipad are also webkit, ensure setting
    if(this.iphone || this.ipad){
    	this.webkit = true;
    }
    
  //  alert('toolkit.js is webkit:' + this.webkit + ' ' + agt);
}
is = new Is(); 

/******* End Browser detection ******/	

/**
	add a help item to the UI
*/
function addTooltip(meme_id, thema){
/* 
*/
  
  TooltipManager.options = {cssClassName: thema, 
		delayOver: 200, 
		delayOut: 1000, 
		shiftX: 5, 
		shiftY: 5,
        className: thema, 
        width: 200, 
        height: null, 
        draggable: false, 
        minimizable: false, 
        maximizable: false, 
        showEffect: Element.show, 
        hideEffect: Element.hide};

  // TooltipManager.init();
  TooltipManager.addURL("tooltip_"+meme_id, "http://www.extentech.com/uimodules/docs/docs_minimal_detail.jsp?meme_id="+meme_id,200,300);
  
}

/**
	 get the width of the browser window
*/ 
function getBrowserWidth(){
// detect browsers and determine window size	
var myWidth = 0, myHeight = 0;
  if( typeof( window.innerWidth ) == 'number' ) {
    //Non-IE
    return window.innerWidth;
  } else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
    //IE 6+ in 'standards compliant mode'
    return document.documentElement.clientWidth;
  } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
    //IE 4 compatible
    return document.body.clientWidth;
  }
}


/**
 get the height of the browser window
*/ 
function getBrowserHeight(){
	
	if( typeof( window.innerWidth ) == 'number' ) {
	    //Non-IE
	    return window.innerHeight;
	  } else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
	    //IE 6+ in 'standards compliant mode'
	    return document.documentElement.clientHeight;
	  } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
	    //IE 4 compatible
	    return document.body.clientHeight;
	  }
}
	


/**
 add a timeout to the Prototype.js AJAX responses to handle
 long-running REST calls without a timeout

// from:  http://codejanitor.com/wp/2006/03/23/ajax-timeouts-with-prototype/
*/
function callInProgress (xmlhttp) {
	switch (xmlhttp.readyState) {
		case 1:
		case 2:
		case 3:
			return true;
			break;

	// Case 4 and 0
		default:
		return false;
		break;
	}
}
function showFailureMessage() {
	showError('Server Timeout. Server is unable to respond in time.');
}

// Register global responders that will occur on all AJAX requests
/**/
if(Ajax != undefined){
	Ajax.Responders.register({
		onCreate: function(request) {
			request['timeoutId'] = window.setTimeout(
				function() {
					// If we have hit the timeout and the AJAX request is active, abort it and let the user know
					if (callInProgress(request.transport)) {
						// request.transport.abort();
						// showFailureMessage();
						// Run the onFailure method if we set one up when creating the AJAX object
						if (request.options['onFailure']) {
							request.options['onFailure'](request.transport, request.json);
						}
					}
				},
				120000 // set high for long queries -- seems to have random effect
			);
		},
		onComplete: function(request) {
			// Clear the timeout, the request completed ok
			window.clearTimeout(request['timeoutId']);
		}
	});
}


/**
	deletes a doc
*/
function deleteDoc(midx){
	Dialog.confirm('Permanently Delete '+midx+'?', {
	    okLabel: 'delete',
		top: 100,
		width:200,
		height:150,
		className:  'extentech',
	    id: 'delete_prompt',
	    cancel:function(win) {
	    		try{
					parent.showStatus('Delete canceled.')
	    		}catch(e){;}
			},
	    ok:function(win) {
	    	parent.showStatus('deleting '+midx+'...');
	    	new Ajax.Request('/workbook/id/'+midx+'/xml/workbook/delete/0' , {
					method: 'get',
					onSuccess: function(transport){
						parent.showStatus('Deleted: ' + transport.responseText);
					},
					onFailure: function(){ 
						var response = transport.responseText || "failure";     
						parent.showStatus("Delete failed: " + response); 
					}
				});
				return true;
	    	}
	   });
}


/**
	get a local scoped element
*/
function getElement(name){
	return $(name);
}

/**
 	make a div appear/disappear
*/
function appear(d){
	d = $(d);
	var vx = false;
	try{
		vx = d.visible();
		// alert(vx);
	}catch(e){
	//	alert(e);
	}
	
	if(vx){
		try{
			new Effect.SwitchOff(d);
		}catch(e){;}
	}else{
		try{
			new Effect.Appear(d);
		}catch(e){;}
		// new Effect.Highlight(d);
	}
}
/**
	create a new spreadsheet...
*/
function createNewSpreadsheet(theme){
	var midz = -1;
	var urlx = '/workbook/id/-1/json/workbook/getid/';
	new Ajax.Request(urlx , {
			method: 'get',
			onSuccess: function(transport){
				midz = transport.responseText.evalJSON().midi;
				showStatus("Created new spreadsheet with id: " + midz);
				createWindow('New Spreadsheet', '/grid/grid.jsp?maximize=true&meme_id='+midz, theme);
				uiWindowing.reloadFileMenu();
			},
			onFailure: function(transport){ 
				var response = transport.responseText || "failure";     
				showError("Unable to create new spreadsheet: " + response); 
			}
		});	
}

/**
	create a new doc...
*/
function createNewDoc(theme){
	var midz = -1;
	var urlx = '/doc/id/-1/json/document/getid/';
	new Ajax.Request(urlx , {
			method: 'get',
			onSuccess: function(transport){
				midz = transport.responseText.evalJSON().midi;
				showStatus("Created new doc with id: " + midz);
				createWindow('New Doc', '/doc_edit/doc.jsp?maximize=true&meme_id='+midz, theme);
				uiWindowing.reloadFileMenu();
			},
			onFailure: function(transport){ 
				var response = transport.responseText || "failure";     
				showError("Unable to create new doc: " + response); 
			}
		});	
}

// TODO: make this less annoying
function saveDoc(){

/*
	try{
	if(uiWindowing.getActiveSheet()==null){
		showInfoDialog("TIP: To save your changes, hit the 'save' button or 'ctrl+s' key while editing your spreadsheet.", "extentech");
	}else{
		if(uiWindowing.getActiveSheet().book!=null){
			if(uiWindowing.getActiveSheet().book.dirty){
				uiWindowing.getActiveSheet().book.promptSave();
			}
		}
	}
	}catch(e){;}
*/
	
}

// wrap Prototype AJAX binding to a div container to standardize handling
function ajaxBind(div, url){
	
	var _divx = $(div);
	if(_divx == null) // hmmm not found...
		return;
		
	if(is.ie){
		_divx.innerHTML = "";
		new Ajax.Updater(div,
		url ,
		{
			method: 'get',  
			evalScripts: true,  
			onSuccess:function(transport){
				_divx.style.overflow = 'auto';
			},
			onFailure: function(transport){ 
				var response = transport.responseText || "failure";     
				parent.showError("Communication problem with " +url+ ":<br>" + response); 
			},
			insertion: Insertion.Top
		});
		_divx.style.overflow = 'auto';
	}else{
		new Ajax.Updater(div,
			url ,
			{
				method: 'get',  
				evalScripts: true,  
				onSuccess:function(transport){
					_divx.setStyle({overflow:'auto'});
				},
				onFailure: function(transport){ 
					var response = transport.responseText || "failure";     
					parent.showError("Communication problem with " +url+ ":<br>" + response); 
				}
			});
		_divx.setStyle({overflow:'auto'});
	}
}

// populate the cellrange box
function setCellRangeBoxText(txt){
	try{
		$('cellrangebox').setValue(txt);	
	}catch(e){
		; // very ignorable
	}
}


// populate the cell edit box
function setCellEditBoxText(lbfx){
	try{
		var elem = $('celleditbox');
		elem.setValue(lbfx);
	}catch(e){
		// normal when not in grid... showError('setCelleditBoxText failed: ' + e.toString());
	}
}

// call an ajax method and output results to status
function ajaxCall(url){
	//alert(url);
	new Ajax.Request(url , {
		method: 'get',
		onSuccess: function(transport){
			showStatus('success: ' + transport.responseText);
		},
		onFailure: function(){ 
			var response = transport.responseText || "failure";     
			showError("AJAX request failed: " + response); 
		}
	});
}

function getActiveWindow(){
	var activeWin = Windows.getFocusedWindow();
	var theId = activeWin.getId();
	theId = theId+'_content';
	return $(theId);
}

/**
	bummer we need this here as a way to get global handles... 
*/
/**
	Get the active sheet that is being worked on.  Note that this class could
	be instantiated either in the grid iframe, where we have a 'sheet' variable
	available, or outside of the iframe where we could have multiple sheets.
**/
function getActiveSheet(){

	try{
		if(parent.sheet != undefined){
			return parent.sheet;
		}
	}catch(e){;}
	
	try{
		if(uiWindowing)
			return uiWindowing.getActiveSheet();
	}catch(e){;}
	
	try{	
		if(parent.uiWindowing)
			return parent.uiWindowing.getActiveSheet();	
	}catch(e){;}
	
	try{
		if(parent.parent.uiWindowing)
			return parent.parent.uiWindowing.getActiveSheet();	
	}catch(e){;}
	
	try{
		if(top.uiWindowing)
			return top.uiWindowing.getActiveSheet();	
	}catch(e){;}
	
	
	// oops
	showError('Could not find active sheet.');

}

/**
 * given element, return the parent frame's window/contentWindow
 * Browser-specific
 */
function srcWindow(el) {
	if (el.ownerDocument.parentWindow) { // IE and Safari require, but works for Firefox too
		var frame= el.ownerDocument.parentWindow.frameElement;
		return frame.contentWindow;
    } else if (el.ownerDocument.defaultView) { // Works for Firefox, DOM level 2 standard
        return el.ownerDocument.defaultView;
	}
	return null;
}


// Deal with user login links

// set the user login div with a valid login
function setUserDiv(id,username){
	try{
		var userdivtxt = '&nbsp;<a href="javascript:createWindow(\'edit user data\',\'/uimodules/user/user_update.jsp\',\'extentech\');" onMouseOver="ddrivetip(\'Click to edit your user information\')"; onMouseOut="hideddrivetip()">';
		userdivtxt += username;
		userdivtxt += '</a>&nbsp;'
		// <a href="javascript:createDialogWindow(\'sign on\',\'/uimodules/user/login.jsp?intro=true\',\'extentech\');" onMouseOver="ddrivetip(\'<b>click to sign out</b>\')"; onMouseOut="hideddrivetip()">';
		//userdivtxt += '<img src="/themes/icons/dd_arrow.gif" title="sign out" width="16" height="16" border="0" align="absmiddle" class=\'rteImage\'></a>&nbsp;';
				
		$('user_login_links').innerHTML = userdivtxt;
	}catch(e){
		showError(e);
	}
}



	/*********************************** LOGGING *******************************************/	

	/* Debug Logging for FF or IE (sorry, that's all for now!)*/
	/* TODO: replace with Debug window ...*/
	var dLog= function(s) { if (typeof console!="undefined") return console.log(s); else if (typeof Debug!="undefined") return Debug.write(s); }
	
	/** Add an event to the event handling
	**/
	function addEvent( obj, type, fn ) {
	   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 );
	   }
	 }
	function removeEvent( obj, type, fn ) {
	   if ( obj.detachEvent ) {
		obj.detachEvent( 'on'+type, obj[type+fn] );
		obj[type+fn] = null;
	   } else
		obj.removeEventListener( type, fn, false );
	 }


 	/*********************************** EVENT HANDLING *******************************************/	
    /* Deprecated, needed for grid resize as the event passed in is an object
	*/
	function evtAttach(obj, eString, method) {
		 if (obj.attachEvent) {	// IE
			for (var i= 1; i+1 < arguments.length; i+=2) {				
				obj.attachEvent('on' +arguments[i], arguments[i+1]);	
			}
		} else if (obj.addEventListener) {
			for (var i= 1; i+1 < arguments.length; i+=2) {							
				obj.addEventListener(arguments[i], arguments[i+1], false);		// assume no capture for now
			}
		} else {
			for (var i= 1; i+1 < arguments.length; i+=2) {				
	            obj['on'+arguments[i]]= arguments[i+1];
	        }
		}	
	}
	/* detach one or more events to Object obj
		cross-browser tested - ALMOST!!
		usage:  evtDetach(OBJECT, eventName, method[, eventName, method ...])
	*/
	function evtDetach(obj, eString, method) {
		if (obj.detachEvent) {
			for (var i= 1; i+1 < arguments.length; i+=2) {				
				obj.detachEvent( 'on' + arguments[i], arguments[i+1]);	
				obj['on' + arguments[i]] = null;
			}
		
		} else if (obj.removeEventListener) {
			for (var i= 1; i+1 < arguments.length; i+=2) {							
				obj.removeEventListener( arguments[i], arguments[i+1], false);		// assume no capture for now
			}
		} else {
			for (var i= 1; i+1 < arguments.length; i+=2) {				
	            obj['on' + arguments[i]]= null;
	        }
        }
	}
	function evtSwallow(evt) {
		if (window.event /*&& window.event.cancelBubble*/) {	// IE
			 window.event.cancelBubble = true;
		}
		if (evt.cancelBubble)
			evt.cancelBubble= true;
		if (evt && evt.stopPropagation) {
			evt.stopPropagation();
		}	
	}

	/**
		This script and many more are available free online at
		The JavaScript Source!! http://javascript.internet.com
		Created by: Mark O'Sullivan :: http://lussumo.com/
		Jeff Larson :: http://www.jeffothy.com/
		Mark Percival :: http://webchicanery.com/
	*/
	function copy2clipboard(text2copy){
		showStatus('copy2clipboard called: ' + text2copy);
		if (window.clipboardData) {
	    	window.clipboardData.setData("Text",text2copy);
	  	} else {
		    var flashcopier = 'flashcopier';
		    if(!document.getElementById(flashcopier)) {
			      var divholder = document.createElement('div');
			      divholder.id = flashcopier;
			      document.body.appendChild(divholder);
		    }
		    document.getElementById(flashcopier).innerHTML = '';
		    var divinfo = '<embed src="/common/js/_clipboard.swf" FlashVars="clipboard='+escape(text2copy)+'" width="0" height="0" type="application/x-shockwave-flash"></embed>';
		    document.getElementById(flashcopier).innerHTML = divinfo;
	    }
	}
	

	/*********************************** ELEMENT POSITIONING *******************************************/	
/* given object obj, return the position as [left, top] 
	cross-browser tested
*/
    function elementPos(obj) { 
		return Position.cumulativeOffset(obj);
    }
    
	/* returns the parent.tagName of node*/    
    function getParent(node, tagName) {
        while (node != null && 
               node.tagName != tagName)
            node = node.parentNode;
        return node;
	}
    
    /* returns the current mouse position from the evt event object
    	this is relative to the VIEWPORT (ie including scroll offsets of documents);
    
     */
     function curPos(evt) { 
     	var point = [Event.pointerX(evt), Event.pointerY(evt)];
     	return point;
    }
    /*********************************** Element Addition *******************************************/
     /* parameters: 
      * 	id			string unique id required
      * 	tag 		string html tagname
      * 	_parent		Object parent node
      * 
	  *     e.g.: newEl= addElementToDOM("newElementID", "div"); 
				removed the style/css attributes as they only workedin static pages - NR	  
	  
      */
    function addElementToDOM(id, tag, _parent) {
		if ($(id)) return $(id);
    	var newEl;	
				newEl= document.createElement(tag);
				newEl.setAttribute("id", id);
				if (newEl)	{ 
					_parent.appendChild(newEl);
				}		
		return newEl
    }
    

	
	/*********************************** CONSTANT GETTERS *******************************************/	
	var SCROLLBARLEFT= (is.ie)?12:12;	
	var SCROLLBARBOTTOM= (is.ie)?6:12;
	


	/*********************************** WINDOWING/DIALOG *******************************************

	use these functions to display windows and dialogs
	
	DO NOT use 'alert', 'prompt' or other browser-based dialogs
	
	
	
*/

// for use by dialogs that need to submit a form, then close and call a function in the MDI
function submitAndClose(somediv, txt){



}

// open win fs
function fullScreen(thisURL) {
	if(is.ie){
		window.open(thisURL, '', 'fullscreen=yes, scrollbars=auto');
	}else{
	   window.locationbar.visible=false;
	   window.toolbar.visible=false;
	   window.personalbar.visible=false;
	   window.statusbar.visible=false;
	   // Force resolution
	   document.documentElement.setAttribute("width", "1024");
	   document.documentElement.setAttribute("height", "768");
      // Main pulldown menu bar
      window.menubar.visible=false;
     //  BrowserFullScreen();
	}
}

// TODO: move all this window stuff to a class
var erring = false;
var singledoc = false;
// the holders keep the active doc title bar intact
var titleBarHolder = null;
var editBarHolder = null;
var miniStatusBarHolder = null;
var miniErrorBarHolder = null;

// whether to display small error bar
var show_mini_error_bar = false;
var show_mini_status_bar = false;

// the error window
function showError(content){
	if(content == undefined)
		return; // hmmm. spurious call?
		
	var bar = $('errorbar');
	
	var minibar = miniErrorBarHolder;
	if(minibar == null)
		minibar = $('minierrorbar');
	
	// recreate
	if(minibar == null){
		minibar = document.createElement('div');
		miniStatusBarHolder = minibar;
	}
	
	if(bar == null){
		bar = window.parent.document.getElementById('errorbar');
		minibar = window.parent.document.getElementById('minierrorbar');
	}
	
	if (bar !=null){
		bar.className='errorbar';
		
		if(minibar!=null){
			minibar.className='minierrorbar';
			minibar.innerHTML = '<img align="right" src="/themes/icons/tango/16x16/emblems/emblem-unreadable.png" onClick="$(\'minierrorbar\').toggle();" style="cursor:pointer;" title="close error message"><img src="/themes/icons/tango/16x16/status/dialog-error.png" align="absmiddle">&nbsp;ERROR: ' + content;
			minibar.toggle();
		}
		
		var maxd = false;
		try{
		 if(show_mini_error_bar) //only show mini bar instead of big
		 	maxd = uiWindowing.getActiveDoc().maximized;
		}catch(e){;}
		
		if(!bar.visible() && !maxd){
			bar.toggle();
			new Effect.Morph(bar);
			// new Effect.Appear(bar);
		}
		if(bar.getStyle('height')!='30px')
			bar.setStyle({height:'30px'});
		
		content = '<img align="right" src="/themes/icons/tango/16x16/emblems/emblem-unreadable.png" onClick="$(\'errorbar\').toggle();" style="cursor:pointer;" title="close error message"><img src="/themes/icons/tango/32x32/status/dialog-error.png" align="absmiddle">&nbsp;ERROR: ' + content;
		bar.innerHTML = content;	
		// new Effect.Highlight(bar);
	
	// restore coolest theme ever
		bar.setStyle({backgroundColor:'#FF0000'});
		bar.setStyle({backgroundImage:'url(/themes/extentech/alertback.png)'});
		bar.setStyle({backgroundRepeat:'no-repeat'});
		bar.setStyle({zIndex:'101'});
		bar.setStyle({position:'absolute'});
		bar.setStyle({width:'100%'});
		
		erring = true;

		// NEVER CLOSE?
		try{
			setTimeout("hideError()", 16000);	
		}catch(e){;}
	}else if(show_mini_error_bar){

		// just show minibar	
		if(minibar == null)
		minibar = $('minierrorbar');
			// recreate
		if(minibar == null){
			minibar = document.createElement('div');
			miniStatusBarHolder = minibar;
		}
		minibar.innerHTML = '<img align="right" src="/themes/icons/tango/16x16/emblems/emblem-unreadable.png" onClick="$(\'errorbar\').toggle();" style="cursor:pointer;" title="close error message"><img src="/themes/icons/tango/16x16/status/dialog-error.png" align="absmiddle">&nbsp;ERROR: ' + content;
		minibar.className='minierrorbar';
		try{
			minibar.toggle();
		}catch(e){;}
	}
}

/**
	pops up a 3 second info window... 
*/
var stimeout =3;
function showInfoDialog(content, theme) {
	var imgsrc= "<img src='/themes/icons/tango/32x32/status/dialog-information.png' style='float:left; margin-right:-32px;'>";
	
	Dialog.info(imgsrc + content,
	 {windowParameters: {className: theme,
	 	width:250,
		height:150},
	showProgress: true});
	setTimeout("infoTimeout()", 1000)
}
function infoTimeout() {
  stimeout--;
  if (stimeout >0) {
   // Dialog.setInfoMessage(stimeout + "s ...")
	setTimeout("infoTimeout()", 1000)
}
  else
    Dialog.closeInfo()
}

// the alert window
function showStatus(content){
	if(content == undefined)
		return; // hmmm. spurious call?
	
	////debug('status: ' + content);
	
	// showInfoDialog(content,'extentech'); // implements total windowing mayhem
	
	var bar = $('statusbar');
	
	miniStatusBarHolder = $('ministatusbar');
	if(miniStatusBarHolder == null){ // recreate
		miniStatusBarHolder = document.createElement('div');
	}
	try{
		if(bar == null)
			bar = window.parent.document.getElementById('statusbar');
	}catch(e){;}
	if (bar !=null){
		bar.className='statusbar';
		
		if(miniStatusBarHolder!=null && show_mini_status_bar){
			try{
				miniStatusBarHolder.className = 'ministatusbar';
				miniStatusBarHolder.innerHTML  = '<img align="right" src="/themes/icons/tango/16x16/emblems/emblem-unreadable.png" onClick="$(\'statusbar\').toggle();" style="cursor:pointer;" title="close status message"><img src="/themes/icons/tango/16x16/status/dialog-information.png" align="absmiddle">&nbsp;' + content;
				miniStatusBarHolder.toggle();
			}catch(e){;}
		}
		
		var maxd = false;
		try{
			if(show_mini_status_bar) // only show mini status instead of big if desired
		 		maxd = uiWindowing.getActiveDoc().maximized;
		}catch(e){;}
		if(!bar.visible() && !maxd){
			bar.toggle();
		}
		if(bar.getStyle('height')!='30px')
			bar.setStyle({height:'30px'});

		content = '<img align="right" src="/themes/icons/tango/16x16/emblems/emblem-unreadable.png" onClick="$(\'statusbar\').toggle();" style="cursor:pointer;" title="close status message"><img src="/themes/icons/tango/32x32/status/dialog-information.png" align="absmiddle">&nbsp;INFO: ' + content;
		bar.innerHTML = content;	

		// restore coolest theme ever
		bar.setStyle({backgroundColor:'#00FF00'});
		bar.setStyle({zIndex:'100'});
		bar.setStyle({position:'absolute'});
		bar.setStyle({width:'100%'});
		bar.setStyle({backgroundImage:'url(/themes/extentech/infoback.png)'});
		bar.setStyle({backgroundRepeat:'no-repeat'});
		
		try{
			setTimeout("hideStatus()", 12000);	
		}catch(e){;}
	}else {
		// alert(content);
	}
	
}

// show:hide with SwitchOff:down
function toggleUpDown(divname){
	var bar = $(divname);
	if(bar==null)
		return;
	if(!bar.visible()){
//		bar.show();
		new Effect.Appear(bar);
	//	new Effect.Appear(bar);
	}else{
		try{
			new Effect.SwitchOff(bar);
		}catch(e){;}
		// bar.toggle();
	}
}
/**
	done with status message, hide it...
*/
function hideError(){
	var bar = $('errorbar');
	var minibar = miniErrorBarHolder;
	if(minibar == null)
		minibar = $('minierrorbar');
	if(bar == null){
		bar = window.parent.document.getElementById('errorbar');
		minibar = window.parent.document.getElementById('minierrorbar');
	}
	if (bar !=null){
		try{
			bar.style.height="25px";
			minibar.style.height="25px";
			new Effect.Fold(bar);	
			new Effect.Fold(minibar);
			// new Effect.Fade(bar);	
		}catch(e){;}
	}
	try{
		bar.innerHTML = '';
		minibar.innerHTML='';
	}catch(e){;}
	
	erring = false;
}

/**
	done with status message, hide it...
*/
function hideStatus(){
	var bar = $('statusbar');
	var minibar = miniStatusBarHolder;
	if(minibar == null)
		minibar = $('ministatusbar');
	if(bar == null){
		bar = window.parent.document.getElementById('statusbar');
		minibar = window.parent.document.getElementById('ministatusbar');
	}
	if (bar !=null){
		try{
			bar.style.height="25px";
			minibar.style.height="25px";
			new Effect.Fold(bar);	
			new Effect.Fold(minibar);
		}catch(e){;}
	}
	bar.innerHTML = '';
	minibar.innerHTML = '';
	erring = false;
}

// cascading and arranging
var idx = 0;
var menuOffset = 70;
var wincount = 0;
var xidx = 0;
var cascade = 0;
var cOffset = 23; // what is it?
var activeWindowTitles = new Array();

// edit win 
function createWindow(title,  module, theme, scrolls, height){
	var ht = height;
	if(ht==null)
		ht=500;
		
	if(activeWindowTitles.indexOf(title)>-1){
		////debug('already have a: ' + title);
		Windows.close(title);
// 		title += wincount++;
	}
	if(module.indexOf('?')>-1)
		module += '&frame='+title;
	else
		module += '?frame='+title;
	
	var lx = 320;
	var wx = getBrowserWidth() - (lx+10);
	if(height!=null)
		ht = getBrowserHeight() - 100;
	
	//openAlert('creating window: ' + title);
	////debug('creating window: ' + title);
	// Windows with an URL as content
	var winx = new Window(title, {title: title, className: theme, 
	  top:80, left:lx, width:wx, height:ht, gridX:10, gridY:10,
	  destroyOnClose: true,
	  resizable: true, 
	  url:module,
	  showEffectOptions: {duration:0}
	  })
	if(scrolls)
		winx.content.setStyle({ overflowY:'scroll' });
	else
		winx.content.setStyle({ overflow:'hidden' });
	
	winx.setDestroyOnClose(true);
	
 	winx.showCenter();
	activeWindowTitles.push(title);	
	// WindowStore.show(winx);
	// WindowStore.init();
	 winx.show();
	// return winx; // causes [Object] errors!
}

// edit win 
function createBigWindow(title,  module, theme, scrolls){
	if(activeWindowTitles.indexOf(title)>-1){
		////debug('already have a: ' + title);
		Windows.close(title);
// 		title += wincount++;
	}
	if(module.indexOf('?')>-1)
		module += '&frame='+title;
	else
		module += '?frame='+title;
	
	//openAlert('creating window: ' + title);
	////debug('creating window: ' + title);
	// Windows with an URL as content
	var winx = new Window(title, {title: title, className: theme, 
		  top:25, left:330, width:850, height:530, gridX:10, gridY:10,
		  destroyOnClose: true,
		  resizable: true, 
		  url:module,
		  showEffectOptions: {duration:0}
		  })
	if(scrolls)
		winx.content.setStyle({ overflowY:'scroll' });
	else
		winx.content.setStyle({ overflow:'hidden' });
	
	winx.setDestroyOnClose(true);
 	
 	// winx.showCenter(); // hateful over centering
	activeWindowTitles.push(title);	
	// WindowStore.show(winx);
	// WindowStore.init();
	winx.show();
}

// create user interface dialogs
function createSheetDialog(title,  module, theme, w, h){

	var wdx = 350;
	var htx = 375;
	if(w != null)
		wdx = w;
		
	if(h != null)
		htx = h;
		
	if(theme == null)
		theme = 'extentech';

	// Windows with an URL as content
	var dlg = new Window(title, {title: title, className: theme, 
	  width:wdx, height:htx,
	  destroyOnClose: true,
	  minimizable:      false,
	  maximizable:      false,
	  closable:			true,
	  resizable: 		true,
	  draggable:			false,
	  url:module,
	  opacity:1,
	  cancel:function(win) {
	  	////debug("validate cancel panel"); 
	  	return true;
	  },
	  showEffectOptions: {duration:0}
	  })
	dlg.content.setStyle({overflow: "hidden"});
	dlg.setDestroyOnClose(true);
	// dlg.show(true);
	dlg.showCenter(true);
	
}

// configurable window
function openWindow(tt, url, theme, x, y, w, h){
	// theme = "'" + theme + "'";
	//alert('opening: ' + tt + url + th + x + y + w + h);
	
	// Windows with an URL as content
	var winx = new Window(tt, {title: tt,
			 className: theme,
			  top:y, left:x, width:w, height:h,
			  //  gridX:10, gridY:10,
			  resizable: 		true,
			  minimizable:      false,
			  maximizable:      false,
	       	  destroyOnClose:   true, 		  

			  /* 20080414 KSC: use passed in module!  url:'/themes/',  */
			  url:url,
			 showEffectOptions: {duration:0}
			})
	//alert(winx);
	winx.content.setStyle({overflow: "hidden"});
	winx.setDestroyOnClose(true);
//20080414 KSC: passing in coordnates so don't automatically center 	winx.showCenter();
	activeWindowTitles.push(tt/*20080414 title*/);	
	winx.show();
	// return winx; // causes [Object] errors
}

// draggable dialog
function createDialogWindow(title,  module, theme){
	createSizedDialogWindow(title, 380, 220, module, theme);
}

/**
	Creates a custom sized draggable dialog window
**/
function createSizedDialogWindow(title, wide, high, module, theme){
	var winx = new Window(title, {title: title, className: theme, 
		  top:70, bottom:0, 
		  left:0, 
		  width:wide, 
		  height:high, 
		  gridX:10, 
		  gridY:10,
		  opacity:5,
      	  zIndex:100,
		  destroyOnClose: true,
		  minimizable:      false,
		  maximizable:      false,
		  resizable: 		true,
       	  destroyOnClose:    true, 
		  url:module,
		  showEffectOptions: {duration:0}
		  })
	winx.content.setStyle({overflow: "hidden"});
	winx.showCenter();
	activeWindowTitles.push(title);	
	winx.show();
}

// edit win 
function createDialog(title,  module, theme){

	var winx = new Window(title, {title: title, className: theme, 
		  width:350, height:300, zIndex:150, opacity:5,
		  resizable: false,
		  //closable: false,
		  minimizable:       false,
		  maximizable:       false,
		  draggable:         false,								  
		  url:module,
       	  destroyOnClose:    true, 
		  showEffectOptions: {duration:0}
		  })
	winx.content.setStyle({overflow: "hidden"});
	winx.showCenter();
	winx.show(true);	
}

function createModalDialog(title,  module, theme){
	var winx = new Window(title, { 
			title: title, 
			className: theme,
			url:module, 
			width:350, 
			height:300, 
			zIndex:100, 
			opacity:1,
			resizable: false,
	  		closable: false,
		  	minimizable:       false,
		  	maximizable:       false,
		  	draggable:         false,			
       	  	destroyOnClose:    true,
  		  	showEffectOptions: {duration:0}
		  	})
	winx.content.setStyle({overflow: "hidden"});
	winx.setContent("select")
	winx.setDestroyOnClose(true);
	winx.showCenter();
	winx.show(true);	
}

function openSave(confirmtxt) {
  Dialog.confirm(confirmtxt, 
                 {top: 150, width:250, className: "extentech_minimus", okLabel: "Yes", cancelLabel:"No",
		  showEffectOptions: {duration:0}})
}

function openAlert(alerttxt) {
 Dialog.alert(alerttxt, {windowParameters: {className: "extentech", top:300,
		  showEffectOptions: {duration:0}}})
}

function openConfirm(confirmtxt) {
  return Dialog.confirm(confirmtxt, 
                 {top: 150, width:250, className: "extentech", okLabel: "Yes", cancelLabel:"No",
		  showEffectOptions: {duration:0}})
}

function confirmDialog(urlx, theme) {
    Dialog.confirm({url: urlx, options: {method: 'get'}}, 
                   {top: 300, width:250, className: theme, okLabel: "Yes", cancelLabel:"No",
		  showEffectOptions: {duration:0}})    
}


function errorDialog(message, theme) {
    Dialog.confirm({url: urlx, options: {method: 'get'}}, 
                   {top: 300, width:250, className: theme,
		  showEffectOptions: {duration:0}})    

//    Dialog.alert(message, {windowParameters: {className: theme}})   
}


/** set the style dynamically **/
function setTheme(themename, doc){
	// get handle to the theme include css
	var preloadtheme = $('themepreload');
	preloadtheme.href='/themes/'+themename+'.css'
	
	
	var theme = $('theme');
	theme.href='/themes/'+themename+'.css'
	
	if(theme.length){ // handle dupes
		for(i = 0;i<theme.length;i++)
			theme[i].href='/themes/'+themename+'.css'	
	}
	
	// iterate the DOM, find the styles starting with 'extentech'

	var kids = document.childNodes;    // Get the list of children
	
	if(doc)
		kids = doc.childNodes;
		
 	var numkids = kids.length;  // Figure out how many children there are
    for(var i = numkids-1; i >= 0; i--) {  // Loop backward through the children
        
        try{
        	var kk = Element.extend(kids[i]);
        	if(kk.setTheme)
        		kk.setTheme(themename);
    	}catch(e){
    		;
    	}
    }
}

/** dynamically load a css include **/
function loadCSS(url){
   var e = document.createElement("include");
   e.src = url;
   e.type="html/css";
   document.getElementsByTagName("head")[0].appendChild(e);
}

/** dynamically load a js include **/
function loadScript(url){
   var e = document.createElement("script");
   e.src = url;
   e.type="text/javascript";
   document.getElementsByTagName("head")[0].appendChild(e);
}

/* reverse the nodes in the document... Funny?*/
function reverse(n) {           // Reverse the order of the children of Node n 
    var kids = n.childNodes;    // Get the list of children
    var numkids = kids.length;  // Figure out how many children there are
    for(var i = numkids-1; i >= 0; i--) {  // Loop backward through the children
        reverse(kids[i]);
		var c = n.removeChild(kids[i]);    // Remove a child
        n.appendChild(c);                  // Put it back at its new position
    }
}

// moved from header.js

function MM_validateForm() { //v3.0
  var i,p,q,nm,test,num,min,max,errors='',args=MM_validateForm.arguments;
  for (i=0; i<(args.length-2); i+=3) { test=args[i+2]; val=MM_findObj(args[i]);
    if (val) { nm=val.name; if ((val=val.value)!="") {
      if (test.indexOf('isEmail')!=-1) { p=val.indexOf('@');
        if (p<1 || p==(val.length-1)) errors+='- '+nm+' must contain an e-mail address.\n';
      } else if (test!='R') { num = parseFloat(val);
        if (val!=''+num) errors+='- '+nm+' must contain a number.\n';
        if (test.indexOf('inRange') != -1) { p=test.indexOf(':');
          min=test.substring(8,p); max=test.substring(p+1);
          if (num<min || max<num) errors+='- '+nm+' must contain a number between '+min+' and '+max+'.\n';
    } } } else if (test.charAt(0) == 'R') errors += '- '+nm+' is required.\n'; }
  } if (errors) showStatus('The following error(s) occurred:\n'+errors);
  document.MM_returnValue = (errors == '');
}
function MM_openBrWindow(theURL,winName,features) { //v2.0
  window.open(theURL,winName,features);
}
function MM_popupMsg(msg) { //v1.0
  showStatus(msg);
}
function MM_preloadImages() { //v3.0
  var d=document; if(d.images){ if(!d.MM_p) d.MM_p=new Array();
    var i,j=d.MM_p.length,a=MM_preloadImages.arguments; for(i=0; i<a.length; i++)
    if (a[i].indexOf("#")!=0){ d.MM_p[j]=new Image; d.MM_p[j++].src=a[i];}}
}
function MM_findObj(n, d) { //v4.0
  var p,i,x;  if(!d) d=document; if((p=n.indexOf("?"))>0&&parent.frames.length) {
    d=parent.frames[n.substring(p+1)].document; n=n.substring(0,p);}
  if(!(x=d[n])&&d.all) x=d.all[n]; for (i=0;!x&&i<d.forms.length;i++) x=d.forms[i][n];
  for(i=0;!x&&d.layers&&i<d.layers.length;i++) x=MM_findObj(n,d.layers[i].document);
  if(!x && document.getElementById) x=document.getElementById(n); return x;
}
function setfocus(){
	if(document.form1 != null){
		if(document.form1.username != null){
			document.form1.username.focus(); 
		}
	}
}


/***********************************************
* Cool DHTML tooltip script II- © Dynamic Drive DHTML code library (www.dynamicdrive.com)
* This notice MUST stay intact for legal use
* Visit Dynamic Drive at http://www.dynamicdrive.com/ for full source code
***********************************************/
/*
document.write('<div id="dhtmltooltip"  style="visibility:hidden; display:none;" class="dhtmltooltip"></div>') //write out tooltip DIV
document.write('<img id="dhtmlpointer"  style="visibility:hidden; display:none;"  class="dhtmlpointer" src="/themes/images/arrow2.gif">') //write out pointer image
var offsetfromcursorX=12 //Customize x offset of tooltip
var offsetfromcursorY=10 //Customize y offset of tooltip
var offsetdivfrompointerX=10 //Customize x offset of tooltip DIV relative to pointer image
var offsetdivfrompointerY=14 //Customize y offset of tooltip DIV relative to pointer image. Tip: Set it to (height_of_pointer_image-1).

var ie=document.all
var ns6=document.getElementById && !document.all
var enabletip=false

var tipobj=document.all? document.all["dhtmltooltip"] : document.getElementById? document.getElementById("dhtmltooltip") : ""

var pointerobj=document.all? document.all["dhtmlpointer"] : document.getElementById? document.getElementById("dhtmlpointer") : ""

function ietruebody(){
return (document.compatMode && document.compatMode!="BackCompat")? document.documentElement : document.body
}


*/

function ddrivetip(thetext, thewidth, thecolor){
	showStatus(thetext);
}
/*
function ddrivetip(thetext, thewidth, thecolor){
if (ns6||ie){
if (typeof thewidth!="undefined") tipobj.style.width=thewidth+"px"
if (typeof thecolor!="undefined" && thecolor!="") tipobj.style.backgroundColor=thecolor
tipobj.innerHTML=thetext
enabletip=true
return false
}
}

function positiontip(e){
if (enabletip){
var nondefaultpos=false
var curX=(ns6)?e.pageX : event.clientX+ietruebody().scrollLeft;
var curY=(ns6)?e.pageY : event.clientY+ietruebody().scrollTop;
//Find out how close the mouse is to the corner of the window
var winwidth=ie&&!window.opera? ietruebody().clientWidth : window.innerWidth-20
var winheight=ie&&!window.opera? ietruebody().clientHeight : window.innerHeight-20

var rightedge=ie&&!window.opera? winwidth-event.clientX-offsetfromcursorX : winwidth-e.clientX-offsetfromcursorX
var bottomedge=ie&&!window.opera? winheight-event.clientY-offsetfromcursorY : winheight-e.clientY-offsetfromcursorY

var leftedge=(offsetfromcursorX<0)? offsetfromcursorX*(-1) : -1000

//if the horizontal distance isn't enough to accomodate the width of the context menu
if (rightedge<tipobj.offsetWidth){
//move the horizontal position of the menu to the left by it's width
tipobj.style.left=curX-tipobj.offsetWidth+"px"
nondefaultpos=true
}
else if (curX<leftedge)
tipobj.style.left="5px"
else{
//position the horizontal position of the menu where the mouse is positioned
tipobj.style.left=curX+offsetfromcursorX-offsetdivfrompointerX+"px"
pointerobj.style.left=curX+offsetfromcursorX+"px"
}

//same concept with the vertical position
if (bottomedge<tipobj.offsetHeight){
tipobj.style.top=curY-tipobj.offsetHeight-offsetfromcursorY+"px"
nondefaultpos=true
}
else{
tipobj.style.top=curY+offsetfromcursorY+offsetdivfrompointerY+"px"
pointerobj.style.top=curY+offsetfromcursorY+"px"
}
tipobj.style.visibility="visible"
if (!nondefaultpos)
pointerobj.style.visibility="visible"
else
pointerobj.style.visibility="hidden"
}
}

function hideddrivetip(){
if (ns6||ie){
enabletip=false
tipobj.style.visibility="hidden"
pointerobj.style.visibility="hidden"
tipobj.style.left="-1000px"
tipobj.style.backgroundColor=''
tipobj.style.width=''
}
}
*/

function hideddrivetip(){
	// showStatus('hidedrivetip');
}
// document.onmousemove=positiontip

// end tooltip


// -------------------------------------------------------------------
// autoComplete (text_input, select_input, ["text"|"value"], [true|false])
//   Use this function when you have a SELECT box of values and a text
//   input box with a fill-in value. Often, onChange of the SELECT box
//   will fill in the selected value into the text input (working like
//   a Windows combo box). Using this function, typing into the text
//   box will auto-select the best match in the SELECT box and do
//   auto-complete in supported browsers.
//   Arguments:
//      field = text input field object
//      select = select list object containing valid values
//      property = either "text" or "value". This chooses which of the
//                 SELECT properties gets filled into the text box -
//                 the 'value' or 'text' of the selected option
//      forcematch = true or false. Set to 'true' to not allow any text
//                 in the text box that does not match an option. Only
//                 supported in IE (possible future Netscape).
// -------------------------------------------------------------------
function autoComplete (field, select, property, forcematch) {
	var found = false;
	for (var i = 0; i < select.options.length; i++) {
	if (select.options[i][property].toUpperCase().indexOf(field.value.toUpperCase()) == 0) {
		found=true; break;
		}
	}
	if (found) { select.selectedIndex = i; }
	else { select.selectedIndex = -1; }
	if (field.createTextRange) {
		if (forcematch && !found) {
			field.value=field.value.substring(0,field.value.length-1); 
			return;
			}
		var cursorKeys ="8;46;37;38;39;40;33;34;35;36;45;";
		if (cursorKeys.indexOf(event.keyCode+";") == -1) {
			var r1 = field.createTextRange();
			var oldValue = r1.text;
			var newValue = found ? select.options[i][property] : oldValue;
			if (newValue != field.value) {
				field.value = newValue;
				var rNew = field.createTextRange();
				rNew.moveStart('character', oldValue.length) ;
				rNew.select();
			}
		}
	}
}

var lastshown = null, lasthiifrm = null;
// this is for the menu divs
function toggleShow(divname){
	var mydiv = $(divname);
	if(lastshown != null)lastshown.style.visibility = "hidden";
	lastshown = mydiv;
	//showStatus(lastshown.id);
	// showStatus(divname +  ' is ' + mydiv.style.visibility); 	
	if(mydiv.style.visibility == "hidden")mydiv.style.visibility = "visible";
	else mydiv.style.visibility = "hidden";
}
