
function getCaptcha(){
    ajax = new AjaxRequest('POST', '/login.php/captcha', true, 3000);
    ajax.setCallback( saEmailCallback );
    ajax.setParameter('type', 'captcha');
    ajax.setParameter('rand', '385651');
    ajax.send();
}

function saSendEmail(page_title){
    is_modal = true;
    var username = util.readCookie('bake_username');
    ajax = new AjaxRequest('POST', '/login.php/check', true, 3000);
    ajax.setCallback( saEmailCallback );
    ajax.setParameter('type', 'email_login');
    if(username){
       var challenge = calcMD5(username) + '05b13afe9c1f4b9f76042f7b64678d8629';
       ajax.setParameter('challenge', challenge);
    }
    ajax.send();
}

function saEmailCallback(XmlResp){
	if(!XmlResp) {
		return false;
	}
	else {
        var msgnb = XmlResp.getElementsByTagName("nb")[0].firstChild.nodeValue;
		var msgdesc = XmlResp.getElementsByTagName("desc")[0].firstChild.nodeValue;
		var act = XmlResp.getElementsByTagName("action")[0].firstChild.nodeValue;
        if( act == 'email_login' ) {
            showSAOverlayBubble(1, 'email');
            var loggedin = XmlResp.getElementsByTagName("logged-in")[0].firstChild.nodeValue;
            if(loggedin > 0) {
                var username = XmlResp.getElementsByTagName("username")[0].firstChild.nodeValue;
                var email = XmlResp.getElementsByTagName("email")[0].firstChild.nodeValue;
                if( username && email ) {
                    var input_elem = document.getElementById("sender_name");
                    if(input_elem) {
                        input_elem.value = username + " <"+email+">";
                    }
                }
                else {
                    var input_elem = document.getElementById("sender_name");
                    if(input_elem) {
                    }
                }
            }
            else {
                var input_elem = document.getElementById("sender_name");
                if(input_elem) {
                }
            }
        }
        else if( act == 'sa_email' ) {
            var msg_sent = XmlResp.getElementsByTagName("msg_sent");
            if( msg_sent[0].firstChild && msg_sent[0].firstChild.nodeValue > 0 ) {
                ShowSAMessage('',msgdesc,'#666');
                setTimeout('saBubbleClose();', 1200);
            }
            else {
                var email_error = document.getElementById("sabubble_email_error");
                if(email_error) {
                    email_error.innerHTML = msgdesc;
                    email_error.style.display = '';
                }
                showSAOverlayBubble(1, 'email');
            }
        }
        else if( act == 'captcha'){
                var captcha_encrypt = XmlResp.getElementsByTagName("encrypt")[0].firstChild.nodeValue;
                var captcha_iv = XmlResp.getElementsByTagName("iv")[0].firstChild.nodeValue;
                var captcha_raw_encrypt = XmlResp.getElementsByTagName("raw_encrypt")[0].firstChild.nodeValue;
                var captcha_raw_iv = XmlResp.getElementsByTagName("raw_iv")[0].firstChild.nodeValue;
                if(document.getElementById('captcha_image')){
                   document.getElementById('captcha_image').src = 'http://www.pricegrabber.com/cptch_img.php?s='+captcha_raw_encrypt+'&iv='+captcha_raw_iv;
                }
                if(document.getElementById('captcha_value')){
                   document.getElementById('captcha_value').value = captcha_encrypt;
                }
                if(document.getElementById('captcha_iv')){
                   document.getElementById('captcha_iv').value = captcha_iv;
                }
        }
    }
}


function showSAOverlayBubble(show,type) {
	showSAOverlay(show);

	if(!show && !saBubbleIsClosed()) {
		document.getElementById('saoverlaybubble').style.left = '-1000px';
                if(document.getElementById('captcha_image')){ document.getElementById('captcha_image').src = 'http://i.pgcdn.com/images/spacer.gif'; }
	}
	else if(show){
                      getCaptcha();
           
           if(document.getElementById('sabubblemsg')) {
	      document.getElementById('sabubblemsg').style.display = (type=='msg' ? '' : 'none'); 
           }
           if(document.getElementById('sabubbleemail')) {
              document.getElementById('sabubbleemail').style.display = (type=='email' ? '' : 'none'); 
           }
		var width = DomUtils.getWindowWidth();
		var height = DomUtils.getWindowHeight();
		var scrollX = DomUtils.getWindowScrollX();
		var scrollY = DomUtils.getWindowScrollY();
		if(width==0 || height==0 || typeof window.opera!="undefined") {
			if(typeof window.opera=="undefined" && document.documentElement.clientWidth) {
				width = document.documentElement.clientWidth;
				height = document.documentElement.clientHeight;
			}
			else {
				width = document.body.clientWidth;
				height = document.body.clientHeight;
			}
		}
         
		if(scrollX==0 || scrollY==0) {
			scrollX = document.documentElement.scrollLeft;
			scrollY = document.documentElement.scrollTop;
		}
		var bwidth = DomUtils.getElementWidth(document.getElementById('saoverlaybubble'));
		var bheight = DomUtils.getElementHeight(document.getElementById('saoverlaybubble'));
        
		document.getElementById('saoverlaybubble').style.top = (scrollY + (height/2) - (bheight/2)) + 'px';
		document.getElementById('saoverlaybubble').style.left = (scrollX + (width/2) - (bwidth/2)) + 'px';
        
	}
}


function saBubbleClose() {
    is_modal = false;
    document.getElementById("sabubble_email_error").style.display = "none";
    document.getElementById('sabubblemsgimage').style.display = 'none';
	showSAOverlayBubble(0,'');
}

function saBubbleIsClosed() {
	return parseInt(document.getElementById('saoverlaybubble').style.left)>0 ? false : true;
}


function showSAOverlay(show) {
    var isIE6 = DomUtils.browser.isIE6();
	if(!show) {
		document.getElementById('login_overlay').style.display = 'none';
        if(isIE6){ 
            document.getElementById('shim').style.display = 'none';
        }
	}
	else {
        var scrollX = DomUtils.getWindowScrollX();
        var scrollY = DomUtils.getWindowScrollY();
        var height = DomUtils.getElementHeight(document.body);
        var width = DomUtils.getElementWidth(document.body);
        if(height < screen.height) {
            height = (screen.height * .8);
        }

        //THIS IS FOR OPERA ONLY 
        //opacity doesn't exist, so we just don't show the overlay
        if (typeof window.opera == "undefined") {
            document.getElementById('login_overlay').style.width = width + 'px';
            document.getElementById('login_overlay').style.height = height + 'px';
            document.getElementById('login_overlay').style.display = 'block';
        }  

        //ADD IFRAME SHIM - for IE6 so select box doesn't show through the popup
        //instead of adding the code for the shim to each page, and potentially missing one, create it manually and append to the body
        if(isIE6){ 
            if(document.getElementById('shim') == null){				
                var shim = document.createElement('iframe');
                shim.setAttribute('src', 'javascript:false;');
                shim.setAttribute('scrolling', 'no');
                shim.setAttribute('frameborder', '0');
                shim.setAttribute('id', 'shim');

                //set needed styles for the shim
                shim.style.zIndex = 99;
                shim.style.display = "none";
                shim.style.position = "absolute";
                shim.style.backgroundColor = "transparent";
                shim.style.top = "0px";
                shim.style.left = "0px";
                document.body.appendChild(shim);
            }  
            document.getElementById('shim').style.filter='progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)'; 
            document.getElementById('shim').style.width = width + 'px';
            document.getElementById('shim').style.height = height + 'px';
            document.getElementById('shim').style.display = 'block';
        }
    }
}


function submitSAOverlay(id_type, p_id, url) {
    var errors = 0;
    var error_msg = '';
    if( document.sa.sender_name.value=='' ) {
        errors = 1;
        error_msg = 'Please supply a name.';
    }
    else if( !isValidEmail(document.sa.friend_e.value) ) {
        errors = 1;
        error_msg = 'Invalid email address.';
    }
    if( errors == 1 ) {
        document.getElementById("sabubble_email_error").innerHTML = error_msg;
    }
    else if( errors == 0 ) {
        saBubbleClose();
        ShowSAMessage('<img src="/images/small_wait.gif" width=16 height=16>','Please hold while we process your request ...','#666666');
        ajax = new AjaxRequest('GET', '/get_prod_email.php', true, 3000);
        ajax.setParameter('sender_name', document.sa.sender_name.value);
        ajax.setParameter('friend_email', document.sa.friend_e.value);
        ajax.setParameter('captcha_value', document.sa.captcha_value.value);
        ajax.setParameter('captcha_response', document.sa.captcha_response.value);
        ajax.setParameter('captcha_iv', document.sa.captcha_iv.value);
        ajax.setParameter('email_msg', document.sa.email_msg.value);
        ajax.setParameter('url', url);
        ajax.setParameter('type', 'sa_email');
        ajax.setParameter('id_type',id_type);
        ajax.setParameter('p_id',p_id);
       ajax.setCallback( saEmailCallback );
        ajax.send();
    }
}


function ShowSAMessage(img,txt,color) {
	document.getElementById('sabubblemsgbody').style.color = color;
	document.getElementById('sabubblemsgbody').innerHTML = txt;
	if(img == '') {
		document.getElementById('sabubblemsgimage').style.display = 'none';
	}
	else {
		document.getElementById('sabubblemsgimage').innerHTML = img;
		document.getElementById('sabubblemsgimage').style.display = '';
	}
	showSAOverlayBubble(1,'msg');
}

function isValidEmail(emailStr) {
    var emailPat=/^(.+)@(.+)$/;
    var specialChars="\\(\\)<>@,;:\\\\\\\"\\.\\[\\]";
    var validChars="\[^\\s" + specialChars + "\]";
    var quotedUser="(\"[^\"]*\")";
    var ipDomainPat=/^\[(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\]$/;
    var atom=validChars + '+';
    var word="(" + atom + "|" + quotedUser + ")";
    var userPat=new RegExp("^" + word + "(\\." + word + ")*$");
    var domainPat=new RegExp("^" + atom + "(\\." + atom +")*$");
    var matchArray=emailStr.match(emailPat);
    if (matchArray==null) {
        return false;
    }
    var user=matchArray[1];
    var domain=matchArray[2];
    if (user.match(userPat)==null) {
        return false;
    }
    var IPArray=domain.match(ipDomainPat);
    if (IPArray!=null) {
        for (var i=1;i<=4;i++) {
            if (IPArray[i]>255) {
                return false;
            }
        }
        return true;
    }
    var domainArray=domain.match(domainPat);
    if (domainArray==null) {
        return false;
    }
    var atomPat=new RegExp(atom,"g");
    var domArr=domain.match(atomPat);
    var len=domArr.length;
    if (domArr[domArr.length-1].length<2 || domArr[domArr.length-1].length>4) {
        return false;
    }
    if (len<2) {
        return false;
    }
    return true;
}

// set this global var if on a secure page for ajax calls
var PG_use_https;
/**
 *  Add user favorite
 *   ajax call to add a user favorite (merchant or brand)
 */ 
function addUserFavorite(user_id, preference_id_type, preference_id, element_id, element_class, element_content, callback)
{

	// if no user id is given, then load the login overlay bubble
	if (!user_id) {
		user_id = util.readCookie('bake_userid');

		// this hack is for IE6 only.... we saved the userid in document.login cuz it cant read cookies well
		if (!user_id && document.login && document.login.loginSuccessUserid) {
			user_id = document.login.loginSuccessUserid;
		}
		// end IE6 hack
		
		if (!user_id) {
			if (document.login) {
				// set login success callback
				// (try adding to favorites again, once login is successful)
				document.login.loginSuccessCallback = function () { addUserFavorite('', preference_id_type, preference_id, element_id, element_class, element_content, callback); };
			}

                        callbackfuncafterlogin = "addUserFavorite('"+(user_id?user_id:"")+"','"+preference_id_type+"','"+preference_id+"','"+element_id+"','"+element_class+"','"+(element_content?element_content:"")+"','"+(callback?callback:"")+"');";
                        //Tracking from where we require user login/registration
                        if (preference_id_type == 'vendor') refer_page = 'Add Brand to Favs';
                        if (preference_id_type == 'merchant') refer_page = 'Add Merchant to Favs';
                        
                        iframe_login('login_registration', callbackfuncafterlogin, refer_page);
			return;
		}
	}

	if (!user_id) {
		return false;
	}
	
//	console.log('addUserFavorite ' + user_id + ' - ' + preference_id_type + ' - ' + preference_id);
	var ajax = new AjaxRequest('GET', '/ajax.php', true, 3000);
	ajax.setParameter('action', 'addUserFavorite');
	ajax.setParameter('user_id', user_id);
	ajax.setParameter('preference_id_type', preference_id_type);
	ajax.setParameter('preference_id', preference_id);
	ajax.setParameter('element_id', element_id);
	ajax.setParameter('element_class', element_class);
	if (element_content) {
		ajax.setParameter('element_content', element_content);
	}
	
	// lame secure hack
	if (PG_use_https) {
		ajax.setParameter('secure', 1);
	}

	if (callback) {
		ajax.setCallback(callback);
	}
	else {
	    ajax.setCallback(addUserFavoriteResponse);
	}
	ajax.send();
}

/**
 * default ajax response after adding user favorite
 */ 
function addUserFavoriteResponse(xml)
{
	// get json
    var data = eval('(' + xml.getElementsByTagName('json')[0].firstChild.nodeValue + ')');

	if (!data['success']) {
		return false;
	}    
	
    if (data['element_id']) {
	    em = document.getElementById(data['element_id']);
	    if (data['element_class']) {
		    em.className = data['element_class'];
		}
	    em.innerHTML = data['message'];
	}

	// update browse favorite stores/brands link if its on the page
	// todo: this should be moved elsewhere
	var store_link = document.getElementById('browse_favorite_stores_link');
	if (store_link && data['preference_id_type'] == "merchant") {
		// update count
		stores_link_count_em = document.getElementById('favorite_stores_count');
		var count = parseInt(stores_link_count_em.innerHTML);
		count++;
		stores_link_count_em.innerHTML = count;
		// update href link
		store_link.href += '/retid[]=' + data['preference_id'];
	}
	var brands_link = document.getElementById('browse_favorite_brands_link');
	if (brands_link && data['preference_id_type'] == "vendor") {
		// update count
		brands_link_count_em = document.getElementById('favorite_brands_count');
		var count = parseInt(brands_link_count_em.innerHTML);
		count++;
		brands_link_count_em.innerHTML = count;
		// update href link
		brands_link.href += '/vendorIds[]=' + data['preference_id'];
	}
        
}

/**
 *	delete a user preference/favorite
 */ 
function deleteUserPreference(user_preference_id, preference_id_type, element_id, callback)
{
	user_id = util.readCookie('bake_userid');

	if (!user_id) {
		LoginOverlay_login();
		return;
	}

	var ajax = new AjaxRequest('GET', '/ajax.php', true, 3000);
	ajax.setParameter('action', 'deleteUserFavorite');
	ajax.setParameter('user_id', user_id);
	ajax.setParameter('secure', 1);
	ajax.setParameter('user_preference_id', user_preference_id);
	ajax.setParameter('preference_id_type', preference_id_type);
	ajax.setParameter('element_id', element_id);
    ajax.setCallback(callback);
	ajax.send();
}

// functions related to login popup to load the external JS files required to handle it
function LoginOverlay_login() {
        if(!loginLoaded) {
                var s2 = document.createElement('script'); s2.src = login_pop_script;
                document.body.appendChild(s2);
        }
        if(!ajaxLoaded) {
                var s1 = document.createElement('script'); s1.src = login_pop_ajax;
                document.body.appendChild(s1);
        }
        LoginOverlay_waitForLoad();
}
function LoginOverlay_waitForLoad() {
        if(!loginLoaded) {
                if (window.login_js) {
                        loginLoaded = 1;
                        ShowLoginMessage('<img src="'+login_pop_wait+'" width=16 height=16>',login_pop_msg,'#666666');}
                else {
                        setTimeout('LoginOverlay_waitForLoad("");',200);
                        return 0;
                }
        }
        if(!ajaxLoaded) {
                if(window.ajax) {
                        ajaxLoaded = 1;
                }
                else {
                        setTimeout('LoginOverlay_waitForLoad("");',200);
                        return 0;
                }
        }
        if (ajaxLoaded && loginLoaded) {
                showLoginBubble();
        }
}
var ajaxLoaded = 0;
var ulistsLoaded = 0;

function addProdToList_callback(HtmlResp) {
   var my_overlay = document.createElement('div');
   my_overlay.setAttribute('id', 'overlay');
   var my_overlaybubble = document.createElement('div');
   my_overlaybubble.setAttribute('id', 'overlaybubble');
   my_overlaybubble.innerHTML = HtmlResp;
   document.body.appendChild(my_overlay);
   document.body.appendChild(my_overlaybubble);
   addProdToListPost();

}

function addProdToList() {
  if(!document.getElementById('overlaybubble')){
     ajax = new AjaxRequest('POST', '/ulists.php/bubbleContent', true, 3000);
     if(ulist_masterid>0){
        ajax.setParameter('masterid', ulist_masterid);
     }
     if(ulist_isbn>0){
        ajax.setParameter('isbn', ulist_isbn);
     }
     ajax.setResponseType('html');
     ajax.setCallback( addProdToList_callback );
     ajax.send();
   }else{
      addProdToListPost();
   }
}

function addProdToListPost() {
  is_modal = true;
  if(!ulistsLoaded) {
	var s2 = document.createElement('script'); s2.src = 'http://www.pricegrabber.com/js/ulists_from_prodpage.js.php?prodpage_lists_only=1';
	document.body.appendChild(s2);
  }
  if(!ajaxLoaded) {
	var s1 = document.createElement('script'); s1.src = 'http://ah.pricegrabber.com/js/classes/ajaxrequest.js';
	document.body.appendChild(s1);
  }
  waitForLoad();
}
function waitForLoad() {
	if(!ulistsLoaded) {
		if(window.ulists_js) { ulistsLoaded = 1; ShowListMessage('<img src="http://i.pgcdn.com/images/small_wait.gif" width=16 height=16>','Please hold while we process your request ...','#666666');}
		else { setTimeout('waitForLoad("");',200); return 0; }
	}
	if(!ajaxLoaded) {
		if(window.ajax) { ajaxLoaded = 1; }
		else { setTimeout('waitForLoad("");',200); return 0; }
	}
	if(ajaxLoaded && ulistsLoaded) { addToList(); }
}
/**
 *
 * $Id: util.js 63843 2009-02-09 23:15:05Z kchiu $
 * $Author: kchiu $
 * $Revision: 63843 $
 * $Name$
 * $Date: 2009-02-09 15:15:05 -0800 (Mon, 09 Feb 2009) $
 *
 * @package     PriceGrabber
 * @category    JavaScript
 *
 * @author      Philip Snyder <philip@pricegrabber.com>
 * @copyright   Copyright &copy; 2006 2007, Philip Snyder, PriceGrabber.com
 * @version     $Revision: 63843 $
 *
 * @todo        Finish documentation.
 */

/**
 * Checks the object to see if it implements a certain function.
 *
 * @access public
 * @since  v1.1
 * @param  string   funcName   Name of function to check for
 * @return boolean
 */



/**
 * Generates an xml string representation of the object.
 *
 * @access public
 * @since  v1.1
 * @param  string   tagname   Tag name to use for the object
 * @return string
 */
/*
Object.prototype.simpleXmlify = function(tagname) {
    var xml = "<"+tagname;
    for (var prop in this) {
        if (!(this[prop] instanceof Function)) {
            xml += " "+prop+"=\""+this[prop]+"\"";
        }
    }
    xml += "/>";
    return xml;
}
*/


/**
 * Finds the index of a value in the array or returns false if not found.
 *
 * @acccess public
 * @since   v1.1
 * @param   mixed val     Value to search array for
 * @return  int | false
 */
Array.prototype.inArray = function(val) {
    for (var i=0; i<this.length; i++) {
        if (this[i] == val) return i;
    }
    return false;
}
// Remove object helper methods from array
Array.prototype.simpleXmlify   = null;
// Remove object helper methods from Error
Error.prototype.simpleXmlify   = null;






/**
 * Generalize namespace for utility functions
 *
 * @access public
 * @since  v1.1
 */
var util = new Object;






/**
 * Manages image cacheing
 *
 * @todo   Confirm this image cacheing scheme works in IE & FF via fiddler
 *
 * @access public
 * @since  v1.1
 */
util.resourceManager = {

    cache: new Array,

    index: new Array,

    /**
     * Handles cacheing and returns the image src of a url.
     * 
     * @access public
     * @since  v1.1
     * @param  string   url
     * @return Image.src
     */ 
    get: function(url) {
        var ptr = util.resourceManager.index.inArray(url);
        if (ptr === false) {
            ptr                                 = util.resourceManager.index.length;
            util.resourceManager.index[ptr]     = url;
            util.resourceManager.cache[ptr]     = new Image;
            util.resourceManager.cache[ptr].src = url;
        }
        return util.resourceManager.cache[ptr].src;
    }
    
};



/**
 * This function returns the name of a given function.
 *
 * It does this by converting the function to a string,
 * then using a regular expression to extract the
 * function name from the resulting code.
 *
 * @access public
 * @since  v1.1
 * @param  Function  f
 * @return string
 */
function funcname(f) {
    var matches = f.toString().match(/function (\w*)/);
    if ((matches == null) || (matches.length == 0)) return "anonymous";
    if (matches.length == 2) return matches[1];
    else return matches.join(',');
}

/**
 * This function returns a string that contains a "stack trace".
 *
 * @access public
 * @since  v1.1
 * @return string
 */
function stacktrace() {
    var s = "";  // This is the string we'll return.
    // Loop through the stack of functions, using the caller property of
    // one arguments object to refer to the next arguments object on the
    // stack.
    for (var a=arguments.caller; a!=null; a=a.caller) {
        // Add the name of the current function to the return value.
        s += funcname(a.callee) + "\n";
        // Because of a bug in Navigator 4.0, we need this line to break.
        // a.caller will equal a rather than null when we reach the end 
        // of the stack. The following line works around this.
        if (a.caller == a) break;
    }
    return s;
}















/***** BEGIN MESSAGE QUEUE *******/




util.MessageQueue = function(type) {
    this.queued = new Array;
    this.containerId = 'message';
    this.type = type || util.MessageQueue.types.ALL;
    this.queueId = util.MessageQueue.queues.length;
    this.waitingForResponse = false;
    util.MessageQueue.queues[this.queueId] = this;
    return this;
};

util.MessageQueue.settings = {
    timer:     null,
    interval:  5, // in seconds
    immediate: true
};

util.MessageQueue.types  = { NONE:0, ERROR:1, DEBUG:2, USER:4, ALL:7 };
util.MessageQueue.queues = [];


util.MessageQueue.attach = function(queue) {
    if (!util.MessageQueue.queues.inArray(queue)) {
        util.MessageQueue.queues.push(queue);
    }
    return true;
}

util.MessageQueue.detach = function(queue) {
    var retain = [];
    var found  = false;
    while (util.MessageQueue.queues.length) {
        var queuePop = util.MessageQueue.queues.pop();
        if (queue !== queuePop) retain.push(queuePop);
        else                    found = queuePop;
    }
    util.MessageQueue.queues = retain;
    return found;
}


util.MessageQueue.prototype.add = function(obj, test) {
    //alert('util.MessageQueue.add called: '+obj.title+' -> '+obj.content);
    test = test === false ? false : true;
    test = true;
    if ((test && this.isMessage(obj)) || !test) {
        //alert(obj);
        this.queued.push(obj);
        //alert(this.queued.toString());
    }
    if (util.MessageQueue.settings.immediate) this.renderNext();
}

util.MessageQueue.prototype.isMessage = function(obj) {
    return obj.implementsProp('title') && obj.implementsProp('content') && obj.implementsProp('type');
} 

util.MessageQueue.prototype.render = function(type) {
    if (this.queued.length > 0) {
        var body = document.getElementsByTagName('body')[0];
        if (body) {
            var types = util.MessageQueue.types;
            type = type <= types.ALL ? type : types.ALL;
            var messages = new Array;
            if (type == types.ALL) {
                messages = this.queued;
                this.queued = new Array;
            } else {
                var retain = new Array;
                for (var i=0; i<this.queued.length; i++) {
                    var msg = this.queued[i];
                    if (msg.type == type) {
                        messages.push(msg);
                    } else {
                        retain.push(msg);
                    }
                }
                this.queued = retain;
            }
            if (!this.container) {
                this.container = document.createElement('div');
                this.container.className = 'messageContainer';
                body.appendChild(this.container);
            }
            for (var i=0; i<messages.length; i++) {
                var mesg = messages[i];
                mesg.displayHandler();
            }
        }
    }
}









util.MessageQueue.prototype.renderNext = function(force) {
    force = force || false;
    if (force) {
        this.waitingForResponse = false;
        clearInterval(this.renderNextTimeout);
        this.renderNextTimeout = null;
    }
    if (this.queued.length > 0) {
        if (!this.waitingForResponse) {
            //Assert.warn('util.MessageQueue.renderNext:displaying from queue '+this.queueId+', queue length = '+this.queued.length);
            var body = document.getElementsByTagName('body')[0];
            if (!body) throw new Error('Unable to find body element');
            var message = null;
            var queueHead = new Array;
            do {
                message = this.queued.shift();
                //Assert.warn('util.MessageQueue.renderNext:shift message type = '+message.type);
                if (message.type != this.type && this.type != util.MessageQueue.types.ALL) {
                    //Assert.warn('util.MessageQueue.renderNext:not all queue, not our message type');
                    queueHead.push(message);
                    message = null;
                }
            } while (!message && this.queued.length > 0);
            while (queueHead.length > 0) {
                this.queued.unshift(queueHead.shift());
            }
            if (message) {
                this.waitingForResponse = true;
                message.displayHandler();
            }
        } else if (!this.renderNextTimer) {
            //Assert.warn('util.MessageQueue.renderNext:setting renderNext timer -- '+this.queued.length+' messages remain');
            this.renderNextTimer = setInterval('util.MessageQueue.queues['+this.queueId+'].renderNext()', 1000);
        }
    }
}




window.messageQueue = new util.MessageQueue(util.MessageQueue.types.ALL);


/***** END MESSAGE QUEUE *******/

















/***** COOKIE MANAGEMENT *****/

/**
 * Creates a cookie via javascript
 *
 * @since  1.1.2.8
 * @access public
 * @param  string    name
 * @param  string    value
 * @param  int       ttl      Time to live, in seconds - defaults to session [optional]
 * @param  string    path     [optional]
 * @param  string    domain   [optional]
 * @param  boolean   secure   [optional]
 * @return void
 */
util.createCookie = function createCookie(name,value) {
    // Support optional arguments
    var argv    = arguments;
    var argc    = arguments.length;
    var ttl     = (argc > 2) ? argv[2]*1000 : null;
    var path    = (argc > 3) ? argv[3]      : null;
    var domain  = (argc > 4) ? argv[4]      : null;
    var secure  = (argc > 5) ? argv[5]      : false;
    // If we have a ttl to work with, calculate the expires
    if (ttl) {
        var expires = new Date();
        expires.setTime(expires.getTime()+ttl);
    }
    // Create the actual cookie
    document.cookie = name + "=" + escape (value) + 
                      ((expires == null) ? "" : ("; expires=" + expires.toGMTString())) + 
                      ((path    == null) ? "" : ("; path=" + path)) + 
                      ((domain  == null) ? "" : ("; domain=" + domain)) + 
                      ((secure  == true) ? "; secure" : "");
}

/**
 * Returns the value of a cookie
 * 
 * @since  1.1.2.8
 * @access public
 * @param  string    name
 * @return string
 */
util.readCookie = function readCookie(name) {
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for(var i=0;i < ca.length;i++) {
        var c = ca[i];
        while (c.charAt(0)==' ') c = c.substring(1,c.length);
        if (c.indexOf(nameEQ) == 0) return unescape(c.substring(nameEQ.length,c.length));
    }
    return null;
}

/**
 * Removes a cookie
 *
 * @since  1.1.2.8
 * @access public
 * @param  string    name
 * @return void
 */
util.eraseCookie = function eraseCookie(name) {
    util.createCookie(name,"",-1);
}


