//***
//* Check out the Javascript Documentation Wiki for details
//***

//XMLHttpRequest(JK)
if( window.XMLHttpRequest || window.ActiveXObject ){
  	if( window.ActiveXObject ){
		var lib = /MSIE 5/.test(navigator.userAgent) ? "Microsoft" : "Msxml2";
  		window.XMLHttpRequest = function(){	return new ActiveXObject(lib + ".XMLHTTP"); };
  	};
}

//String trim(JK)
String.prototype.trim = function () { return this.replace(/^\s*/, "").replace(/\s*$/, ""); }

//*** Custom Javascripts *** (JK)
/*
Function: $
	Returns the element(s)
	Shortcut for document.ElementById

Arguments:
	obj - the object to inspect.

Example:
	>$('myElement').style.display='none';  //same as document.getElementById('myElement).style.dispplay ='none';
	>$('myElement1','myElement2',myElement3').style.display='none'; //same as above for all elements
*/
function $() {
   var es = new Array();
   for (var i = 0; i < arguments.length; i++) {
      var e = arguments[i];
      if (typeof(e) == 'string') { e = document.getElementById(e); }
      if (arguments.length == 1) { return e; }
      es.push(e);
   }
   return es;
}

/*
Function: $type
	Returns the type of object that matches the element passed in.

Arguments:
	obj - the object to inspect.

Example:
	>var myString = 'hello';
	>$type(myString); //returns "string"

Returns:
	'element' - if obj is a DOM element node
	'textnode' - if obj is a DOM text node
	'whitespace' - if obj is a DOM whitespace node
	'arguments' - if obj is an arguments object
	'object' - if obj is an object
	'string' - if obj is a string
	'number' - if obj is a number
	'boolean' - if obj is a boolean
	'function' - if obj is a function
	'regexp' - if obj is a regular expression
	'class' - if obj is a Class. (created with new Class, or the extend of another class).
	'collection' - if obj is a native htmlelements collection, such as childNodes, getElementsByTagName .. etc.
	false - (boolean) if the object is not defined or none of the above.
*/
function $type(obj){
	if (!$defined(obj)) return false;
	if (obj.htmlElement) return 'element';
	var type = typeof obj;
	if (type == 'object' && obj.nodeName){
		switch(obj.nodeType){
			case 1: return 'element';
			case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace';
		}
	}
	if (type == 'object' || type == 'function'){
		switch(obj.constructor){
			case Array: return 'array';
			case RegExp: return 'regexp';
			case Class: return 'class';
		}
		if (typeof obj.length == 'number'){
			if (obj.item) return 'collection';
			if (obj.callee) return 'arguments';
		}
	}
	return type;
};

/*
Function: $random
	Returns a random number between two integers passed by arguments 

Arguments:
	min - (integer) minimum range of a random number
	max - (integer) maximum range of a random number

Example:
	>var num = $random(0,100); //returns a random number between 0-100
*/
function $random(min, max){
	return Math.floor(Math.random() * (max - min + 1) + min);
};

/*
Function: $time
	Returns a current time in milliseconds

Arguments:
	nothing

Example:
	>var time = $time(); //returns a time ex)1204311506409 
*/
function $time(){
	return new Date().getTime();
};

/*
Function: $clear
	clears timeout & interval of of the timer id that is passed by an argument 

Arguments:
	id - (pointer) id of the timer 

Example:
    >var myTimer = setTimer(SomeFunction,2000); //sets a timer to excute 'SomeFunction' in 2 sec
	>$clear(myTimer); //clears the 'myTimer' timer
*/
function $clear(timer){
	clearTimeout(timer);
	clearInterval(timer);
	return null;
};


//******(JK)
//Ajax
CB.Ajax = function (url,option) {
	if($_RedirectUrl && $_RedirectUrl != "") {url = $_RedirectUrl + encodeURIComponent(url);}
	if (!url) return;
	var _method = option.method || 'post';	
	var _data = option.data || null;
	var _evalResponse = option.evalResponse || false;
	var _onComplete = option.onComplete || new Function();
	var _onFailure = option.onFailure || new Function();
	var _async = option.async || true;
     
	if (_method.toLowerCase() == 'get') {
		url = url + "?" +_data;	
		_data = null;	
	}
	var _request = 	new window.XMLHttpRequest;
	_request.onreadystatechange = _CheckStateChange;
	_request.open(_method, url, _async);
			
	function _CheckStateChange() {
		if (_request.readyState == 4) {
           if (_request.status == 200) {
			   var text = _request.responseText;
			   var xml = _request.responseXML;
			   if (_evalResponse) { eval('(' + text + ')'); }
			   _onComplete(text,xml);
           } else {
			   _onFailure(_request.status );
           }
       	} 
	}
	return {
		send: function() {
			_request.send(_data);
		}
	};	
}

//toQueryString
CB.ToQueryString = function (source) {
	var qs = new Array();
	for(var property in source) {
		var value = source[property];
		var pqs = function(val) { qs.push([encodeURIComponent(property), encodeURIComponent(val)].join('=')); }
		if (typeof(value) == 'array') { value.each(pqs) }
		else { pqs(value) }
	}
	return qs.join('&');
}
//******


// designed to be used as a singleton object, so you probably shouldn't inherit from this guy
CB.AJAX = function (){
    return {
        currentVisiblePopup: null,
        isPopupLocked: false,
        
        // Cross browser compatible creation of XmlHttpRequest object
        createRequest: function(){
            var request;

            // IE
            try{
	            request = new ActiveXObject("Msxml2.XMLHTTP");
            }
            catch(e){
	            try{
		            request = new ActiveXObject("Microsoft.XMLHTTP");
	            } 
	            catch(oc){
		            request = null;
	            }
            }
        	
            // Mozilla
            if(!request && typeof XMLHttpRequest != "undefined") {
	            request = new XMLHttpRequest();
            }
        	
            return request;
        },
        
        // Fires a callback, sending data to page, with the response handled by handler
        submitCallback: function(data, page, handler, lockPopups){
            var request = this.createRequest();
            if(request){
	            if(typeof ajaxRelativePrefix != 'undefined'){
		            // prefix page with relative path prefix var that was inserted by MatrixPage
		            page = ajaxRelativePrefix + page;

		            // prepare request
		            request.open('POST', page, true);
		            request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

		            // when the request is answered, relayResponse() will be called
		            request.onreadystatechange = function(){ CB.AJAX.relayResponse(request, handler); };

                    CB.AJAX.isPopupLocked = lockPopups;
		            // fire off the request
		            request.send(data);
	            }
	            else{
		            // relative path var not found, cannot correctly set path to AJAX page
		            handler(false, 'Relative prefix not found (be sure to use Page.HasAjax).');
	            }	
            }
            else{
	            // request object wasn't instantiated
	            handler(false, 'Unable to create request object.');
            }
        },
        
        // Passes response data from a callback to the handler function
        relayResponse: function (request, handler){
            var responseText;
            var index;
            if(request.readyState == 4){
                try{
	                if(request.status == 200){
		                responseText = request.responseText;
            			
		                // ugly hack for international pages adding extra HTML
		                index = responseText.indexOf("<!DOCTYPE");
		                if(index != -1){
			                responseText = responseText.substring(0, index);
		                }
            			
		                // success, give response text to handler function
		                CB.AJAX.isPopupLocked = false;
		                handler(true, responseText);
	                }
	                else{
		                // page returned error code (such as 404)
		                CB.AJAX.isPopupLocked = false;
		                handler(false, 'Ajax page returned error code ' + request.status + '.');
	                }
	            }
	            catch(e){
	                // i hate this, but for now we need to eat the error.  we don't have a sure way of tracking errors
	            }
            }
        },
        hidePopups: function () {
            if (CB.AJAX.currentVisiblePopup && !CB.AJAX.isPopupLocked) {
	            CB.AJAX.currentVisiblePopup.hide();
	        }
	        if (window.hideCurrentPopup) {   // this will close windows in the other popup management system
                hideCurrentPopup();
            }
	    }
    };
} ();

// the base object of all AJAX widgets.  These will most likely be comprised of DIVs
CB.AJAX.Popup = function ()
{
    function onDocumentClick (evt,target){
        var shadowBox;
        if (!CB.AJAX.currentVisiblePopup.isModal){
            if(target){//if i don't know the target then I can't determine anything
                shadowBox = CB.e('shadowAJAX');
                if(!shadowBox || !shadowBox.lastAnchor || shadowBox.lastAnchor.id != target.id){
                    CB.AJAX.hidePopups();
                }
            }
        }
    }
	// find X coordinate of an element:  anchor - the element we are trying to position relative to, element - the element we are positioning
	function findX(anchor, element, halign)	{
	    // we need to be really intelligent about what we spit back out.
		var curleft = 0;
		var leftcenter = anchor.offsetWidth / 3;
		var rightcenter = anchor.offsetWidth - leftcenter;
		if(anchor.offsetParent){
			while(anchor.offsetParent){
				curleft += anchor.offsetLeft;
				anchor = anchor.offsetParent;
			}
		}
		else if(anchor.x){
			curleft += anchor.x;
		}
		
		if(halign && halign === 'flush'){
		    if (curleft > CB.Window.getWidth() / 2) {
		        // we are on the right side of the window		    
		        return (curleft + (leftcenter * 3)) - element.scrollWidth;
		    } else {
		    	// we are on the left side of the window
		    	return curleft;
		    }
		}
		else {
		    if (curleft > CB.Window.getWidth() / 2) {
		        // we are on the right side of the window
		        return (curleft + rightcenter) - (element.scrollWidth);
		    }
		    else {
		        // we are on the left side of the window
		        return curleft + leftcenter;
		    }
	    }
	}

	// find Y coordinate of an element
	function findY(anchor, element)	{
		var curtop = 0;
		if(anchor.offsetParent){
			while(anchor.offsetParent){
				curtop += anchor.offsetTop;
				anchor = anchor.offsetParent;
			}
		}
		else if(anchor.y){
			curtop += anchor.y;
		}
		
		// using a hard number feels like a hack, but it should serve us well
		// I used to use anchor.offsetHeight, but it counts padding and so is inconsistent
		if (!CB.Window.ie) {
		    if (curtop + 20 + element.offsetHeight > CB.Window.getScrollHeight()) {
		        return CB.Window.getScrollHeight() - element.offsetHeight;
		    }
		    else {
		        return curtop + 20;
		    }
		}
		else {
		    if (curtop + 15 + element.offsetHeight > CB.Window.getScrollHeight()) {
		        return CB.Window.getScrollHeight() - element.offsetHeight;
		    }
		    else {
		        return curtop + 15;
		    }
		}
	}
	
    return {
        containerElm: null,
        parentContainer: null,
        isModal: false,
        halign: null,
    
        initialize: function(container, options){
            // do some initialization here
            this.containerElm = container;
            if (container) {
                this.parentContainer = container.parentNode;
            }
            if(options){
                this.isModal = options.isModal;
                this.halign = options.halign;
            }
        },
    
        // options is an optional variable where you can stuff any desired parameters for onShow
        show: function(anchor, options, anchorOffsetX, anchorOffsetY){
            // we have to get our shadow
            var shadowBox = CB.e('shadowAJAX');
            var diff,i;
            if (!shadowBox) {
                shadowBox = document.createElement("div");
                shadowBox.className = 'cb_style shadowing';
                shadowBox.style.textAlign = 'left';
                shadowBox.id = 'shadowAJAX';
                CB.EventUtils.addEventListener(shadowBox,'click',function(evt,target){evt.cancelBubble = true;});
                
                document.body.appendChild(shadowBox);
            }
            
            if (this.containerElm  && !CB.AJAX.isPopupLocked) {
                // now we need to hide all the other windows
                CB.AJAX.hidePopups();
                if (this.isModal){
                    var modal = CB.e('modal_background');
                    if(!modal){
                        modal = document.createElement("div");
                        modal.id = 'modal_background';
                        document.body.appendChild(modal);
                    }
                    modal.style.width = CB.Window.getScrollWidth() + 'px';
                    modal.style.height = CB.Window.getScrollHeight() + 'px';
                    modal.style.left = '0px';
                    
                    // ugly, but, this is how we have to reposition it to be seen
                    shadowBox.x = ((CB.Window.getWidth()/2) - (this.containerElm.scrollWidth/2));
                    shadowBox.y = ((CB.Window.getHeight()/2) - (this.containerElm.scrollHeight/2));
                    shadowBox.style.left = shadowBox.x + 'px';
                    shadowBox.style.top = shadowBox.y + 'px';
                    if(CB.Window.ie7 || CB.Window.gecko || CB.Window.khtml){
                        shadowBox.style.position = 'fixed';
                    }
                }else if (anchor) {
                    // if we have an anchor, then we can position based on it
                    //  otherwise, just use our current position
                    anchor.blur();
                    shadowBox.x = findX(anchor, this.containerElm, this.halign);
                    shadowBox.y = findY(anchor, this.containerElm);
                    
                    if(arguments.length == 4 && anchorOffsetX != null && anchorOffsetY != null)
                    {
                        shadowBox.x += anchorOffsetX;
                        shadowBox.y += anchorOffsetY;
                    }
                    
                    shadowBox.style.left = shadowBox.x + 'px';
                    shadowBox.style.top = shadowBox.y + 'px';
                    shadowBox.lastAnchor = anchor;
                    shadowBox.style.position = 'absolute';
                }
                
                this.onShow(options);
                shadowBox.appendChild(this.containerElm);
                
                if (!CB.Window.ie) {  // we are not in IE
                    shadowBox.style.height = (this.containerElm.scrollHeight + 1) + 'px';
                    shadowBox.style.width = (this.containerElm.scrollWidth + 4) + 'px';
                }
                else {  // we are in IE
                    shadowBox.style.height = (this.containerElm.scrollHeight + 6) + 'px';
                    shadowBox.style.width = (this.containerElm.scrollWidth + 6) + 'px';
                }
                this.containerElm.style.visibility = 'visible';
                shadowBox.style.visibility = 'visible';
                CB.AJAX.currentVisiblePopup = this;
                CB.Window.scrollDown((shadowBox.offsetHeight + shadowBox.y - CB.Window.getScrollTop()) - CB.Window.getHeight(), 8);
                CB.EventUtils.addEventListener(document,'click',onDocumentClick);
            }
        },
        
        onShow: function(anchor, options) {
            // this function is designed to be overridden  (technically an onBeforeShow)
            // so if you have any special processing that happens when your div is opened, then
            // change onShow so that it points to a different/custom function
        },
        
        hide: function() {
            var shadowBox = CB.e('shadowAJAX');
            if (shadowBox) {
                shadowBox.style.visibility = 'hidden';
            }
            
            if(this.isModal){
	            var modal = CB.e('modal_background');
	            if(modal){
	                modal.style.left = '-3000px';
	            }
	        }
            
        	if (this.containerElm.style.visibility != 'hidden') {
	            this.containerElm.style.visibility = 'hidden';
	            this.parentContainer.appendChild(this.containerElm);
	            this.onHide();
	        }
	        CB.EventUtils.removeEventListener(document,'click',onDocumentClick);
        },
        
        onHide: function() {
            // this function is designed to be overridden  (technically an onAfterShow)
            // so if you have any special processing that happens when your div is closed, then
            // change onHide so that it points to a different/custom function
        }
        
        // TODO: have a max height and width variable to check against and use that to determine scrolling
        // TODO: if the window resizes, then reposition yourself (this may require us to hold onto the anchor's coordinates)
    };
} ();






// Provides base functions for using AJAX
// Cross browser compatible creation of XmlHttpRequest object
function createRequest()
{
	return request = new window.XMLHttpRequest();
}

// Fires a callback, sending data to page, with the response handled by handler
function submitCallback(data, page, handler, showMsg)
{
    if(showMsg){
        if(document.title && document.title.indexOf('WAT') > -1 && document.title.indexOf('RunDeveloper') > -1){
            alert('You are using the old submitCallback method.  Please update your AJAX call to use CB.AJAX.submitCallback.  Callback sent to ' + page);
        }
    }
    
	var request = createRequest();
	if(request)
	{
		if(typeof ajaxRelativePrefix != 'undefined')
		{
			// prefix page with relative path prefix var that was inserted by MatrixPage
			page = ajaxRelativePrefix + page;

			// prepare request
			request.open('POST', page, true);
			request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

			// when the request is answered, relayResponse() will be called
			request.onreadystatechange = function(){ relayResponse(request, handler); };

			// fire off the request
			request.send(data);
		}
		else
		{
			// relative path var not found, cannot correctly set path to AJAX page
			handler(false, 'Relative prefix not found (be sure to use Page.HasAjax).');
		}	
	}
	else
	{
		// request object wasn't instantiated
		handler(false, 'Unable to create request object.');
	}
}

// Passes response data from a callback to the handler function
function relayResponse(request, handler)
{
    var responseText;
    var index;
	if(request.readyState == 4)
	{
		if(request.status == 200){
			responseText = request.responseText;
			
			// ugly hack for international pages adding extra HTML
			index = responseText.indexOf("<!DOCTYPE");
			if(index != -1)
			{
				responseText = responseText.substring(0, index);
			}
			
			// success, give response text to handler function
			handler(true, responseText);
		}
		else
		{
			// page returned error code (such as 404)
			handler(false, 'Ajax page returned error code ' + request.status + '.');
		}
	}
}
