/* -*- mode: C;-*--------------------------------------------------------------
 * (c)2005-2010 Copyright InfoStreet, Inc.
 * Use without the permission of InfoStreet Inc. is strictly prohibited.
 * Contact InfoStreet for more details (http://www.infostreet.com)
 *
 * Name:           $RCSfile: ss_JSLibrary.js,v $
 * Author:         Nick Garcia <nick@infostreet.com>
 * Created On:     Oct 10, 2007
 * Last Modified:  $Date: 2010/09/02 23:02:29 $
 * Last Modifier:  $Author: ben $
 * Version:        $Revision: 1.207 $
 *
 * Grand Combined Javascript Library
 *-----------------------------------------------------------------------------*/

// ####### utils.js #######
// General Utility Functions


/*
 * Determine browser using non agent means
 */
var moz = (document.getElementById) ? true : false;
var ie = (document.all) ? true : false;

/*
 * For moving elements around
 */
var basicDragging = 0;
var ss_dragZIndex = 0;
var adjustZIndex = true;
var resizingFolders;
var resizingHeaders;
var dragElement = null;
var mouseOffset;
var dragHeightOffset = 0;
var defaultTree;
var popupDragStartX;
var popupDragStartY;
var popupOuterDiv;
var draggables = new Object(); // To store coordinates and sizes.
var SS_MousePos = {x: 0, y: 0};
var draggingCallbacks = new Array();
var startDragCallbacks = new Array();
var stopDragCallbacks = new Array();

/*
 * for popup windows
 */
var popupWindows = new Object();
var popupHighZindex = 9999;
var resizingPopupWindow;
var popupResizeStart;
var popupSizeStart;

/*
 * Keeps track of AJAX requests that are processing...
 */
var AJAXprocessing = new Array();
var AJAXreusables = new Object();
var AJAXinprogress = new Object();

/*
 * For autocompletion.
 */
var currentTB;
var completionCall = AJAXRequest(getCompletions);
var completionTimeout;
var completionLoading = false;
var completionOffset = 0;
var completionOffsetLeft = 0;
var selectedCompletion;
var completionsFocused;
var openCompletion = false;

/*
 * for disabling listKeyHandler function if any popup is open.
 */
var jsPopupOpen = 0;

/* 
 * Keeps track of lines (ss_drawLine)
 */
var lineContainers = new Array();

/*
 * for ajax list template functions
 */
var firstLoad = true;
var maxPerList;
var order;
var orderBy;
var pageStart;
var headersLoaded;

/*
 * this variable is for storing configure menu urls.
 */
 var ss_configureMenuUrls = new Array();
/*
 * Determines whether or not an entered field is numeric.
 */
function isNumeric(sText)
{
   var ValidChars = "0123456789.";
   var IsNumber=true;
   var Char;
   for (i = 0; i < sText.length && IsNumber == true; i++)
      {
      Char = sText.charAt(i);
      if (ValidChars.indexOf(Char) == -1)
         {
            return false;
         }
      }
   return IsNumber;
}

/*
 * Return the page x coordinate of an object's top left corner
 */
function getPosX( obj ){
  if (obj.offsetParent && obj.offsetParent != document){
    return obj.offsetLeft + getPosX( obj.offsetParent );
  } else {
    return 0;
  }
}
function getPosY( obj ){
  if (obj.offsetParent && obj.offsetParent != document){
    return obj.offsetTop + getPosY( obj.offsetParent );
  } else {
    return 0;
  }
}

/* 
 * return true if x, y coordinates are within the boundaries of a given object
 */
function isInside( obj, x, y ){
  objX = getPosX( obj );
  objY = getPosY( obj );
  objW = obj.offsetWidth;
  objH = obj.offsetHeight;
         
  return ( objX < x && x < (objX + objW) && 
           objY < y && y < (objY + objH) );
}

/*
 * function openWindow 
 * Opens a new popup window in four sizes(Small, Medium, Large, full size) at
 * the center of screen
 * I took this from navigation/src/www/main.js because I need it to be here.
 * - Nick
 */ 

popupSizeTable = new Object();
popupSizeTable['xx-small']  = 100;
popupSizeTable['x-small']   = 200;
popupSizeTable['small']     = 300;
popupSizeTable['medium']    = 400;
popupSizeTable['large']     = 500;
popupSizeTable['x-large']   = 600;
popupSizeTable['xx-large']  = 700;
popupSizeTable['xxx-large'] = 800;
popupSizeTable['huge']      = 900
popupSizeTable['max']      = 9999;

var blockedPopupInfo;

function openWindow(size, URL, winName, refreshOnClose){
  if (size) {
    size = size.toLowerCase();
    // old sizes
    if (size == 'small'){
      width = 350;
      height = 300;
    } else if (size == 'medium'){
      width = 550;
      height = 500;
    } else if (size == 'large') {
      width = 700;
      height = 600;
    }
    // newer more flexible sizes
    else if (size.split('/').length == 2) {
      sizes = size.split('/');
      width = popupSizeTable[sizes[0]];
      height = popupSizeTable[sizes[1]];

      /* max size is 90% of screen size */
      if (width == 9999) {
        width = Math.round(0.9 * screen.availWidth);
      }
      if (height == 9999) {
        height = Math.round(0.9 * screen.availHeight);
      }
    } 
  } else {
    width = screen.width-2;
    height = screen.height-2;
  }
  if (!winName){
    winName = "win" + Math.round(100000*Math.random());
  }
  if (!URL){
    URL = '';
  }

  popupWidth = width;
  popupHeight = height;

  newWin = window.open(URL, winName,"width=" + width +
                       ",height=" + height +
                       ",resizable,scrollbars,");

  if (!newWin) {
    // The user's browser has popup blocking enabled.
    blockedPopupInfo = {url: URL, name: winName, size: size,
                        refresh: refreshOnClose};
    showPopup("PopupBlocked");
    return;
  }

  if (refreshOnClose) {
    setDocDomain();
  }

  return newWin;
}

function openBlockedPopup() {
  openWindow(blockedPopupInfo.size, blockedPopupInfo.url,
             blockedPopupInfo.name, blockedPopupInfo.refresh);

  blockedPopupInfo = null;
  hidePopup("PopupBlocked");
}

/*
 * Find and detach templates from their parent containers, 
 * and make them "visible" by default if they were hidden.
 */
function getTemplate( id, detach ){
  templateObj = document.getElementById( id );

  if (detach){
    templateObj.parentNode.removeChild( templateObj );

    if (templateObj.style.visibility == "hidden"){
      templateObj.style.visibility = "visible";
    }
  }
  return templateObj;
}

/* 
 * Append a second (modifier) class to the given object's class.
 * Eventual previous modifier is removed.
 * This is used to add Hover, Active etc additional attributes.
 */
function addClassModifier( obj, modifierClass ){
  //obj.className = obj.className.replace( /^(\w* ?).*/, "$1 "+modifierClass );
  obj.className += " " + modifierClass
}

/*
 * Remove the modifier class (if any) from this element.
 */
function removeClassModifier( obj, modifierClass ){
  if ( !obj ) {
    return; 
  }
  
  if (!modifierClass) {
    // If no class name is passed in, use default behavior and remove all but
    // the first class.
    obj.className = obj.className.replace( /^(\w*) .*/, "$1" );
  } else {
    // Otherwise, remove the specified class only and leave everything else.
    re = eval("/" + modifierClass + "/g");
    obj.className = obj.className.replace(re, "");
  }
} 

/*
 * Resize the window
 */
function getAdjustedHeight() {
  content     = document.getElementById( "ScrollableContent" );
  menubar     = document.getElementById( "MenuBar" );
  toolbar     = document.getElementById( "ToolButtonContainer" );
  bottombar   = document.getElementById( "BottomBar" );
  searchbar   = document.getElementById( "SearchBar" );
  filterbar   = document.getElementById( "FilterBar" );
  titlebar    = document.getElementById( "PopupTitle" );
  tabs        = document.getElementById( "TabsTable" );
  ownerbox    = document.getElementById( "OwnerBox" );
  breadcrumbs = document.getElementById( "BreadCrumb" );
  body        = document.getElementsByTagName("body")[0];
  sizeanchor  = document.getElementById( "SizeAnchor" );

  if (!sizeanchor) {
    // This is here to get around the problem of this function being called
    // before the page is finished drawing.
    return;
  }

  decorations = 110;
  
  var newHeight;
  if (content.scrollHeight > content.offsetHeight) {
      newHeight = content.scrollHeight
  } else {
      newHeight = sizeanchor.offsetTop;
  }

  if (menubar) { newHeight += menubar.offsetHeight };
  if (toolbar) { newHeight += toolbar.offsetHeight };
  if (bottombar) { newHeight += bottombar.offsetHeight };
  if (filterbar) { newHeight += filterbar.offsetHeight };
  if (titlebar) { newHeight += titlebar.offsetHeight };
  if (tabs) { newHeight += tabs.offsetHeight };
  if (ownerbox) { newHeight += ownerbox.offsetHeight };
  if (breadcrumbs) { newHeight += breadcrumbs.offsetHeight };

  newHeight += decorations;

  if (newHeight > ( screen.availHeight - 30 ) ) {
    newHeight = screen.availHeight - 30;
  }
 
  if (newHeight < minResizeHeight) {
    newHeight = minResizeHeight;
  }

  return newHeight;
}

function getAdjustedWidth() {
  content     = document.getElementById( "ScrollableContent" );
  menubar     = document.getElementById( "MenuBar" );
  toolbar     = document.getElementById( "ToolButtonContainer" );
  filterbar   = document.getElementById( "FilterBar" );
  tabs        = document.getElementById( "TabsTable" );
  ownerbox    = document.getElementById( "OwnerBox" );
  body        = document.getElementsByTagName("body")[0];

  decorations = 12;
  
  var newWidth = content.scrollWidth;

  if (menubar && menubar.offsetWidth > newWidth) {
    newWidth = menubar.offsetWidth;
  }

  if (toolbar) {
    toolbarWidth = toolbar.offsetWidth;
    if (filterbar) {
      toolbarWidth += filterbar.offsetWidth + 12; /* +12 for margins */
    }
    if (toolbarWidth > newWidth) {
      newWidth = toolbarWidth;
    }
  }

  if (tabs) {
    if (ownerbox) {
      if ((tabs.offsetWidth + ownerbox.offsetWidth) > newWidth) {
          newWidth = tabs.offsetWidth + ownerbox.offsetWidth;
      }
    } else if (tabs.offsetWidth > newWidth) {
      newWidth = tabs.offsetWidth;
    }
  }

  if (body.scrollWidth > body.offsetWidth) { newWidth = body.scrollWidth };

  newWidth += decorations;

  if (newWidth < minResizeWidth) {
    newWidth = minResizeWidth;
  }
  
  return newWidth;
}

 
/* Resize stuff */
doNotResizeMe = false;
minResizeWidth = 0;
minResizeHeight = 0;

function noResize() {
  doNotResizeMe = true;
}

function setMinimumSize(width, height) {
  if (width) {
    minResizeWidth = width;
  }
  if (height) {
    minResizeHeight = height;
  }
}

function resizeWin() {

  if (doNotResizeMe) {
      return;  // Stop processing if requested
  }
  
  newHeight = getAdjustedHeight();
  newWidth = getAdjustedWidth();
  if ( !newHeight || !newWidth) return;
  window.resizeTo(newWidth, newHeight);

  /* start collecting info to move the window to make 
     sure it's on the screen */
  newX = window.screenLeft;
  newY = window.screenTop;

  moveWindow = false;

  if (newX == undefined) {
    /* For Mozilla */
    newX = window.screenX;
    newY = window.screenY;
  }

  if (newX + newWidth > screen.availWidth) {
    newX = screen.availWidth - newWidth;
    if (newX < 0) { newX = 0 };
    moveWindow = true;
  }
  
  if (newY + newHeight > screen.availHeight) {
    newY = screen.availHeight - newHeight;
    if (newY < 0) { newY = 0 };
    moveWindow = true;
  }
  
  if (moveWindow) {
    window.moveTo(newX, newY);
  }
}

function resizeContent() {
  fixedTop     = document.getElementById( "FixedTop" );
  fixedBottom  = document.getElementById( "FixedBottom" );
  content      = document.getElementById( "ScrollableContent" );
  body         = document.body;

  heightTop    = fixedTop.offsetHeight;
  heightBottom = fixedBottom.offsetHeight;
  heightTopStyle    = heightTop + "px";
  heightBottomStyle = heightBottom + "px";

    // fixedTop.style.height    = heightTop;
    // fixedBottom.style.height = heightBottom;
    body.style.paddingTop = heightTopStyle;
    body.style.paddingBottom = heightBottomStyle;
    content.style.top = heightTopStyle;
    content.style.bottom = heightBottomStyle;

  /* Resize me if I'm a popup */
  if (window.opener && window.opener != window) {
    resizeWin();
  }
}

function reloadWindow() {
  if (!(window.opener && window.opener != window)) {
    document.location = document.location;
  }
}

function reloadParent() {
  //setDocDomain();
  try {
    currentOpenerHref = window.opener.document.location.href;
  } catch (e) {
    currentOpenerHref = "";
  }
  try {
    index = myOpenerHref.indexOf('?');
  } catch (e) {
    return;
  }
  if (index > -1) {
    var end = myOpenerHref.indexOf('?');
    myOpenerHref = myOpenerHref.substring(0, end);
  }

  if (currentOpenerHref.indexOf('?') > -1) {
    var end = currentOpenerHref.indexOf('?');
    currentOpenerHref = currentOpenerHref.substring(0, end);
  }

  if (myOpenerHref == "") {
    /* Couldn't get an href from the opener, so try and reload it so
       as not to give the impression that it's broken */
    window.opener.location.reload();
  } else  if (myOpenerHref && currentOpenerHref == myOpenerHref) {
    window.opener.location.reload();
  }
}

function setDocDomain() {
  if (document.domain) {
    // Set the domain to the base domain (ie infostreet.com)
    
    parts = document.domain.split('.');
    ext = parts[parts.length - 1];
    domain = parts[parts.length - 2];
    document.domain = domain + '.' + ext;
  }
}

function loggedInUser() {
  if (isLoggedIn()) {
    s = document.cookie.split("Basic_Hosting=");
    s2 = s[1].split("==")[1].split(";")[0];
    return s2.slice(1);
  } else {
    return "not-logged-in"
  }
}

function getLeft(obj) {
  /* Returns the "left" style for absolutely positioned elements */
  if (obj.style.left) {
    leftPos = Number(obj.style.left.slice(0, -2));
    return leftPos;
  }

  return 0;
}

function baseURL(url) {
  if (url) {
    // Get the base of a url, 
    // ie: baseURL("http://foo.com/map/view.pyt?xyx=a/b/c") = "http://foo.com/map/"

    //First remove all arguments from url ( anything after ? )
    if (url.indexOf("?") != -1 ) {
      url = ( url.split("?") )[0];
    }

    var stringurl = url;
    parts = stringurl.split("/");
    newurl = "";
    whichparts = parts.length - 1;
    for (i=0; i<whichparts; i++) {
      newurl = newurl + parts[i] + "/";
    }
    return newurl;
  }
}

function busyBar(bbName, w, h, speed, cellNum) {
  // site constants that should not be modified by developers
  borderWidth = "1";
  borderColor = "Highlight";
  backgroundColor = "HighlightText";

  // bar container
  bb = document.createElement("div");
  bb.id = "busyBar_"+bbName;

  //bb.style.visibility = "visible";
  bb.style.position = "relative";
  bb.style.overflow = "hidden";
  bb.style.width = w;
  bb.style.height = h;
  bb.style.backgroundColor = backgroundColor;
  bb.style.borderColor = borderColor;
  bb.style.borderWidth = borderWidth;
  bb.style.borderStyle = "solid";
  bb.style.fontSize = "1px";
  // container for cells
  cellsSpan = document.createElement("span");
  cellsSpan.id = "cells_"+bbName;

  cellsSpan.style.position = "absolute";
  cellsSpan.style.left = "-"+(h*2+1)+"px";
  cellsSpan.style.backgroundColor = backgroundColor;
  cellsSpan.fontSize = "1px";

  // add the cellSpan to the bar container
  bb.appendChild(cellsSpan);

  for( i=0; i<cellNum; i++ ){
    newCell = document.createElement("span");
    newCell.className = "ProgressSpan";
    newCell.style.backgroundColor = borderColor;
    newCell.style.position = "absolute";
    newCell.style.left = "-" + ((h*i)+i) + "px";
    newCell.style.fontSize = "1px";
    newCell.style.width = h;
    newCell.style.height = h;
    
    var opacity = (100-i * 1.1 * (100/cellNum)) / 100;
    newCell.style.MozOpacity = opacity
    newCell.style.opacity = opacity

    if (ie) {
      newCell.style.filter = "alpha(opacity=" + opacity * 100 + ")";
    }
    
    // add the latest cell to the cellsSpan
    cellsSpan.appendChild(newCell);
  }

  // instance variables
  var bbI = cellsSpan;
  bbI.main = bb;
 
  bbI.cellNum = cellNum;
  bbI.bbName = bbName;
  bbI.h = h;
  bbI.w = w;
  bbI.speed = speed;
  bbI.ctr = 0;
  bbI.show = function(){ this.main.style.visibility="visible"; }
  bbI.hide = function(){ this.main.style.visibility="hidden"; }
  bbI.tid = setInterval( "startBusyBar(cellsSpan)",speed );
  bbI.stop = function(){ clearInterval(this.tid); }
  
  return bbI;
}

function startBusyBar(cellsSpan){

  if( parseInt(cellsSpan.style.left) + cellsSpan.h+1 - (cellsSpan.cellNum*cellsSpan.h+cellsSpan.cellNum) > cellsSpan.w){
    cellsSpan.style.left=-(cellsSpan.h*2+1)+"px";
    cellsSpan.ctr++;
  }
  else {
    cellsSpan.style.left = ( parseInt(cellsSpan.style.left) + cellsSpan.h+1 ) + "px";
  }
}

function cloud(title, desc){
  div = document.createElement("div");
  div.style.backgroundColor = "HighlightText";
  div.style.position = "absolute";
  if(moz){
    screenW = window.innerWidth;
    screenH = window.innerHeight;
    //div.style.MozOpacity=0.90
  }

  if(ie){
    screenW = document.body.offsetWidth;
    screenH = document.body.offsetHeight;
    //div.style.filters.alpha.opacity=90; 
  }

  div.style.width = "100%";
  div.style.height = "100%";
  div.style.top = 0;
  div.style.left = 0;
  
  header = document.createElement("div");
  header.className = "PopupContentTitle PopupContentTitleDiv";
  titleNode = document.createTextNode(title);
  descNode = document.createTextNode(desc);

  description = document.createElement("div");
  description.className = "Content ContentDiv";

  content = document.createElement("div");
  content.className = "Content ContentDiv";

  header.appendChild(titleNode);
  description.appendChild(descNode);

  div.appendChild(header);
  div.appendChild(description);
  div.appendChild(content);
  
  document.body.appendChild(div);
  return div;
}

function busyPopCloud(title, desc) {
  if (title == "") {
    title = "Loading...";
  }
  if (desc == "") {
    desc = "Please Wait...";
  }
  var busyCloud = cloud(title, desc);
  var myBusyBar = busyBar("busyPopBar", 300, 15, 90, 10);
  busyCloud.lastChild.appendChild(myBusyBar.main);

}



/*
 * This function displays the progress bar, it is just activity bar
 * it does not update on any percent, it requires an ID of div
 * divID to put the progressBar into, 
 * function is called from templat/progressBar.xsl 
 * same template defines the div
 */

function displayProgressBar(divID , width, height, speed, cellNumber) {

  var divObj = document.getElementById(divID);
  divObj.style.width = "100%";

  var myBusyBar = busyBar( "busyPopBar", width, height, speed, cellNumber );
  divObj.appendChild( myBusyBar.main );
}


/*
 * This function goes through all the forms in a page and looks for a
 * text element or file input elment, it puts the focus on the element found
 * it is called in templates/page.xsl, so that whereever page.xsl is called 
 * this focus occurs
 */

function focusFirst() {
  for (var i = 0; i < document.forms.length; i++) {
    var formObj = document.forms[i];
    if (formObj){
      for (var j = 0; j < formObj.elements.length; j++) {
        var formElement = formObj.elements[j];
        if (formElement.type == "text" || formElement.type == "file"){
          formElement.focus();
          return;
        }
      }
    }
  }
}

/* These functions are for displaying tooltips on mouseover of any element */
function createToolTip(id, tipText) {
  // tooltipTemplate comes from menu.js
  var tooltip = tooltipTemplate.cloneNode(true);
  var pageBody = document.getElementById("PageBody");
  tooltip.firstChild.nodeValue = tipText;
  tooltip.id = id;

  pageBody.insertBefore( tooltip, fixedTop );
}

function showTip(tipName, event) {
  var e = event;
  if (tipName) {
    tip = document.getElementById(tipName);

    if (tip) {
      tip.style.visibility = "visible";
      tip.style.left = event.clientX + 5; // - tip.offsetWidth;
      tip.style.top = event.clientY + 20;
      tip.style.zIndex = popupHighZindex + 1;
    }
  }
}

function hideTip(tipName) {
  if (tipName) {
    tip = document.getElementById(tipName);
    if (tip) {
      tip.style.visibility = "hidden";
    }
  }
}

function removeTipById (tipId) {
  if (tipId) {
    tip = document.getElementById(tipId);
    if (tip) {
      tip.parentNode.removeChild(tip);
    }
  }  
}

function stopEventBubble(event) {
  if (!event) {
    event = window.event;
  }
  event.cancelBubble = true;
  if (event.stopPropagation) {
    event.stopPropagation();
  }
}

function getProperUrl(applicationName, pylet) {
  /* 
   * This function returns a url to a pylet in another package preserving the
   * username in the path if it exists.  We had to add this because of the
   * changes made to our urls where we moved the username out of the domain and
   * into the path.
   *
   * If the function is being called from a path without the username in it,
   * it will return /package/pylet.
   *
   * If the function is being called from a path with the username in it, it
   * will return /package/username/pylet.
   */
  var currentUrl = document.location.pathname;
  var parts = currentUrl.split("/");

  if (parts.length == 4) {
    username = parts[2];
    return "/" + applicationName + "/" + username + "/" + pylet;
  } else {
    return "/" + applicationName + "/" + pylet;
  }
}

/*************************
 * AJAX Helper Functions *
 *************************/
 
function AJAXRequest(callback, uid) {
  var xmlHttp;
  try {
    xmlHttp = new XMLHttpRequest();
  } catch (e) {
    try {
      xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
      try {
          xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
      } catch (e) {
        alert("Your browser does not support AJAX.  Please try a different browser.");
        return false;
      }
    }
  }

  xmlHttp.onreadystatechange=function() {

    if (xmlHttp.readyState == 4) {
      AJAXprocessing.pop();
      if (!AJAXprocessing.length) {
        hidePopup("AjaxLoading");
      }

      if (xmlHttp.responseText) { 
        if (xmlHttp.responseText.substr(1,4) == "html" ) {
          // Exception errors and login pages are in HTML.
          if(xmlHttp.responseText.indexOf("<title>Sign In</title>") != -1 ) {
            // User is no longer logged in, reload the page to display the
            // login screen.
            document.location.reload(true); 
          } else {
            // Exception error.
            var data = new Object();
            data["error"] = "Communication Error: There was an error communicating with the server.\nPlease try this request again.";
            callback(data);
          }  
          return;
        } else {
          // Process a JSON response.
          var rt = xmlHttp.responseText;
          var isInProgress = AJAXinprogress[callback.toString()];

          try {
            if (isInProgress == undefined || isInProgress == uid) {
              if (rt) {
                var data = eval("(" + rt + ")");
                callback(data);
              } else {
                var data = new Object();
                data["error"] = "No data returned for " + source.nodeName;
                callback(data);
                return;
              }
            }
          } catch(e) {
            err = e.message || e.description;
            if (e.message == "Invalid character") {
              // There are certain characters that IE cannot display that
              // occasionally come up in emails.
              var data = new Object();
              data["error"] = "parseError";
              callback(data);
              return
            }
          }
          return
        }
      }
    }
  }
  return xmlHttp;
}

function AJAXReusable(id, callback) {
  var xmlHttp = AJAXRequest(callback);

  if (AJAXreusables[id]) {
    alert("A reusable AJAX component with id '" + id + "' was already registered.  Specify a different id.");
    return;
  }

  // Store this so that we can use it to reinitialize the object later.
  AJAXreusables[id] = callback;

  return xmlHttp;
}

// This function assigns text values to a dictionary type object creating
// arrays as necessary.
function addNodeValue(data, node, index) {
  if (index != undefined) {
    text = node.childNodes[index].nodeValue.replace(/^[ \s]+|[ \s]+$/g, "");
  } else {
    // Get the text, trimming leading and trailing whitespace
    text = node.firstChild.nodeValue.replace(/^[ \s]+|[ \s]+$/g, "");
  }

  if (data[node.nodeName] == undefined) {
    // If we haven't seen this attribute yet, add it as a string.
    data[node.nodeName] = text;
  } else {
    try {
      // We already have this attribute, so try to append to an array.
      data[node.nodeName].push(text);
    } catch (e) {
      // It wasn't an array, so it must be just a string.  Create a new array.
      data[node.nodeName] = new Array(data[node.nodeName], text);
    }
  }
}

// This is the function that processes the data returned from the server.
function parseXML(node) {
  var data = new Object;

  if (!node.childNodes.length) {
    /* IE will get in here if it gets a None from Python, we don't want to
     * return an empty object, so we return undefined instead. */
    return undefined
  }

  for (var i = 0; i < node.childNodes.length; i++) {
    var currentNode = node.childNodes[i];

    if (currentNode.childNodes.length == 1 &&
        (currentNode.firstChild.nodeType == 3 ||
         currentNode.firstChild.nodeType == 4)) {
      addNodeValue(data, currentNode);
    } else if (currentNode.childNodes.length == 3 &&
               currentNode.childNodes[1].nodeType == 4 ) {
      addNodeValue(data, currentNode, 1);
    } else if (currentNode.nodeType == 1) {
      if (data[currentNode.nodeName] == undefined) {
        data[currentNode.nodeName] = parseXML(currentNode);
      } else {
        try {
          data[currentNode.nodeName].push(parseXML(currentNode));
        } catch (e) {
          data[currentNode.nodeName] = new Array(data[currentNode.nodeName],
                                                 parseXML(currentNode));
        }
      }
    }
  }
  return data
}

// Make a call using AJAX
function makeAJAXCall(xmlHttpObj, url, noLoader, reusableId) {
  if (url.indexOf("pyletOptions") == -1) {
    if (url.indexOf("?") > -1) {
      url += "&pyletOptions=json";
    } else {
      url += "?pyletOptions=json";
    }
  }

  AJAXprocessing.push(1);
  if (noLoader != true) {
    //showPopup("AjaxLoading");
    var al = document.getElementById("AjaxLoading");
    al.style.display = "block";
    setPopupAlignment(al);
    if (noLoader) {
      al.innerHTML = noLoader;
    }
  }

  if (reusableId) {
    callback = AJAXreusables[reusableId];
    var now = new Date();
    
    // Always abort and reinstantiate reusables.  Both Firefox and IE need
    // this.
    xmlHttpObj.abort();
    xmlHttpObj = new AJAXRequest(callback, now.valueOf());
    AJAXinprogress[callback.toString()] = now.valueOf();
  }

  xmlHttpObj.open("GET", url, true);
  xmlHttpObj.send(null);
}

function makeAJAXFormCall(xmlHttpObj, formObj, formAction){
  var parameters = "pyletOptions=json";
  for (i=0; i<formObj.length; i++) {
    var paramName = formObj[i].name;
    var paramVal = formObj[i].value;
    if ( formObj[i].type == "checkbox" || formObj[i].type == "radio") {
      if (formObj[i].checked ) {
        parameters += ( "&" + formObj[i].name + "=" + encodeURIComponent(formObj[i].value) );
      }  
    } else if (formObj[i].name && formObj[i].value) {
      parameters += ( "&" + formObj[i].name + "=" + encodeURIComponent(formObj[i].value) );
    }  
  } 
  xmlHttpObj.open("POST", formAction, true);
  xmlHttpObj.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  xmlHttpObj.setRequestHeader("Content-length", parameters.length);
  xmlHttpObj.setRequestHeader("Connection", "close");
  xmlHttpObj.send(parameters);
}

function addText(text, parent) {
  newSpan = document.createElement("span");
  textNode = document.createTextNode(text);
  newSpan.appendChild(textNode);
  parent.appendChild(newSpan);

  return newSpan;
}

function setText(text, parent) {
  parent.innerHTML = "";
  addText(text, parent);

  return newSpan;
}

/* Functions for rounded corners */
function NiftyCheck()
{
    if(!document.getElementById || !document.createElement)
            return(false);
    var b=navigator.userAgent.toLowerCase();
    if(b.indexOf("msie 5")>0 && b.indexOf("opera")==-1)
            return(false);
    return(true);
}

function Rounded(selector,bk,color,size){
    var i;
    var v=getElementsBySelector(selector);
    var l=v.length;
    for(i=0;i<l;i++){
        AddTop(v[i],bk,color,size);
        AddBottom(v[i],bk,color,size);
    }
}

function RoundedTop(selector,bk,color,size){
    var i;
    var v=getElementsBySelector(selector);
    for(i=0;i<v.length;i++)
            AddTop(v[i],bk,color,size);
}

function RoundedBottom(selector,bk,color,size){
    var i;
    var v=getElementsBySelector(selector);
    for(i=0;i<v.length;i++)
            AddBottom(v[i],bk,color,size);
}

function AddTop(el,bk,color,size){
    var i;
    var d=document.createElement("b");
    var cn="r";
    var lim=4;
    if(size && size=="small"){ cn="rs"; lim=1}
    d.className="rtop";
    d.style.backgroundColor=bk;
    for(i=1;i<=lim;i++){
        var x=document.createElement("b");
        x.className=cn + i;
        x.style.backgroundColor=color;
        d.appendChild(x);
    }
    el.insertBefore(d,el.firstChild);
}

function AddBottom(el,bk,color,size){
    var i;
    var d=document.createElement("b");
    var cn="r";
    var lim=4;
    if(size && size=="small"){ cn="rs"; lim=1}
    d.className="rbottom";
    d.style.backgroundColor=bk;
    for(i=lim;i>0;i--){
        var x=document.createElement("b");
        x.className=cn + i;
        x.style.backgroundColor=color;
        d.appendChild(x);
    }
    el.appendChild(d,el.firstChild);
}

function getElementsBySelector(selector){
    var i;
    var s=[];
    var selid="";
    var selclass="";
    var tag=selector;
    var objlist=[];
    if(selector.indexOf(" ")>0){  //descendant selector like "tag#id tag"
        s=selector.split(" ");
        var fs=s[0].split("#");
        if(fs.length==1) return(objlist);
        return(document.getElementById(fs[1]).getElementsByTagName(s[1]));
    }
    if(selector.indexOf("#")>0){ //id selector like "tag#id"
        s=selector.split("#");
        tag=s[0];
        selid=s[1];
    }
    if(selid!=""){
        objlist.push(document.getElementById(selid));
        return(objlist);
    }
    if(selector.indexOf(".")>0){  //class selector like "tag.class"
        s=selector.split(".");
        tag=s[0];
        selclass=s[1];
    }
    var v=document.getElementsByTagName(tag);  // tag selector like "tag"
    if(selclass=="")
            return(v);
    for(i=0;i<v.length;i++){
        if(v[i].className==selclass){
            objlist.push(v[i]);
        }
    }
    return(objlist);
}

/* Functions for basic drag and move functionality.  These allow us to set up
 * divs in our pages to be dragged around. */
function getPosition(e) {
  var left = 0;
  var top = 0;

  while (e.offsetParent) {
    left += e.offsetLeft;
    top += e.offsetTop;
    e = e.offsetParent;
  }

  left += e.offsetLeft;
  top += e.offsetTop;

  return {x: left, y: top};
}

function getMouseOffset(target, ev) {
  ev = ev || window.event;

  var docPos = getPosition(target);
  var mousePos = mouseCoords(ev);
  return {x: mousePos.x - docPos.x, y: mousePos.y - docPos.y};
}

function mouseCoords(ev) {
  if (ev.pageX || ev.pageY) {
    return {x: ev.pageX, y: ev.pageY};
  } else {
    return {x:ev.clientX + document.body.scrollLeft - document.body.clientLeft,
            y:ev.clientY + document.body.scrollTop - document.body.clientTop}
  }
}

var dragOptions = new Object;
var dragBoundaryTop = 0;
var dragBoundaryLeft = 0;
var dragStep = 1;
var halfStep = 1;

function addDraggableCoords(dragObject, modified) {
  if (!dragObject.id) {
    dragObject = document.getElementById(dragObject)
  };

  draggables[dragObject.id] = {"offsetTop" : dragObject.offsetTop,
                               "offsetLeft" : dragObject.offsetLeft,
                               "offsetHeight" : dragObject.offsetHeight,
                               "offsetWidth" : dragObject.offsetWidth,
                               "modified" : modified}
}

function makeDraggable(dragObjId, dragHandleId, useGrid, boundaryContainer) {
  var dragObj = document.getElementById(dragObjId);
  var dragHandle = document.getElementById(dragHandleId) || dragObj;
  if (!dragHandle) {
    // The object doesn't exist!  Bail out!
    return;
  }
  var optionsObj = new Object;
  var fixedTop = document.getElementById("FixedTop");

  // This option will tell the object being dragged to obey an invisible grid
  // to snap to when dragging the object around.
  optionsObj.useGrid = useGrid;

  // This option specifies a container that the draggable object is bound to,
  // and cannot escape.
  optionsObj.boundaryContainer = boundaryContainer;

  dragOptions[dragObjId] = optionsObj;

  dragHandle.style.cursor = "move";
  //dragHandle.addEventListener("mousedown", startBasicDrag, false);
  //ss_attachEvent(dragHandle, "mousedown", startBasicDrag);
  dragHandle.onmousedown = startBasicDrag;
  //dragHandle.onmouseup = stopBasicDrag;
  dragObj.isDraggable = true;
  //dragObj.style.zIndex = 9999;

  var desktop = document.getElementById("Desktop");
  var pageBody = document.getElementById("PageBody");

  if (!boundaryContainer) {
    dragObj.parentNode.removeChild(dragObj);
    if (pageBody) {
      pageBody.insertBefore( dragObj, fixedTop );
    } else {
      desktop.appendChild( dragObj );
    }
  }

  //dragObj.parentNode.onmouseup = stopBasicDrag;
}

function addDraggingCallback(func) {
  draggingCallbacks.push(func);
}

function addStopDragCallback(func) {
  stopDragCallbacks.push(func);
}

function addStartDragCallback(func) {
  startDragCallbacks.push(func);
}

function startBasicDrag(event) {
  
  
  event = event || window.event;

  event.cancelBubble = true;
  event.returnValue = false;
  if (event.stopPropagation) { event.stopPropagation() }; 
  if (event.preventDefault) { event.preventDefault() };

  basicDragging = 1;

  for (var i = 0; i < startDragCallbacks.length; i++) {
    startDragCallbacks[i]();
  }

  var w = getTopWindow();
  try {
    var fs = w.document.getElementById("mainSet"); // The main frame
    if (fs) {
      ss_attachEvent(fs, "selectstart", preventSelection);
      ss_attachEvent(fs, "drag", preventSelection);
      ss_attachEvent(document, "selectstart", preventSelection);
      ss_attachEvent(document, "drag", preventSelection);
      ss_attachEvent(document, "mousedown", preventSelection);
    }
  } catch(e) {
    // Ignore.  We're probably in an iframe on another site and getting a
    // security permission error.
  }

  //document.onmousemove = doBasicDrag;
  ss_attachEvent(document, "mousemove", doBasicDrag);

  dragElement = this || window.event.srcElement;

  while (!dragElement.isDraggable) {
    dragElement = dragElement.parentNode;
  }

  ss_dragZIndex = dragElement.style.zIndex;
  ss_attachEvent(document, "mouseup", stopBasicDrag);

  var fixedTop = document.getElementById("FixedTop");
  var optionsObj = dragOptions[dragElement.id];
  if (optionsObj) {
    if (optionsObj.useGrid) {
      dragStep = gridSize;
      halfStep = gridSize / 2;
    } else {
      dragStep = 1;
      halfStep = 1;
    }

    if (optionsObj.boundaryContainer) {
      dragBoundaryTop = optionsObj.boundaryContainer.offsetTop;
      dragBoundaryLeft = optionsObj.boundaryContainer.offsetLeft;
    } else {
      dragBoundaryTop = 0;
      dragBoundaryLeft = 0;
    }
  }
  mouseOffset = getMouseOffset(dragElement, event);
  //addClassModifier(dragElement, "TransHeavy");
  if (adjustZIndex) {
    dragElement.style.zIndex =  ++popupHighZindex
  }
}

function stopBasicDrag(event) {
  basicDragging = 0;
  document.onmousemove = null;

  for (var i = 0; i < stopDragCallbacks.length; i++) {
    stopDragCallbacks[i]();
  }

  if (dragElement) {
    isPopup = popupWindows[dragElement.id];
    if(isPopup) {
      tp = removePX( dragElement.style.top );
      lt = removePX( dragElement.style.left );
      if(lt>0 || tp>0) {
        isPopup["top"] = tp;
        isPopup["left"] = lt;
      }
    }

    dragElement.parentNode.onmouseup = null;
  }

  var w = getTopWindow();

  try {
    var fs = w.document.getElementById("mainSet"); // The main frame
  } catch(e) {
    var fs = false;
  }
  
  if (fs) {
    ss_detachEvent(fs, "selectstart", preventSelection);
    ss_detachEvent(fs, "drag", preventSelection);
    ss_detachEvent(document, "selectstart", preventSelection);
    ss_detachEvent(document, "drag", preventSelection);
    ss_detachEvent(document, "mousedown", preventSelection);
  }
  //removeClassModifier(dragElement, "TransHeavy");
  ss_detachEvent(document, "mouseup", stopBasicDrag);
  if (dragElement && dragElement.id) {
    if (adjustZIndex) {
      if (ss_dragZIndex) {
        dragElement.style.zIndex = ss_dragZIndex;
        ss_dragZIndex = 0;
      } else {
        dragElement.style.zIndex = 0;
      }
    }
    try{
      draggables[dragElement.id].modified = true;
    } catch(e) {}
  }
  dragElement = null;

}

function objectsOverlap(obj1, obj2) {
  // Check the 4 corner points of object1 against the corner points of object2.
  // If any corner point of object1 falls inside the area of object2, return
  // true.

  var obj1Top = obj1.offsetTop + 5;
  var obj1Left = obj1.offsetLeft;
  var obj1Bottom = obj1.offsetTop + obj1.offsetHeight - 5;
  var obj1Right = obj1.offsetLeft + obj1.offsetWidth;

  var obj2Top = obj2.offsetTop + 5;
  var obj2Left = obj2.offsetLeft;
  var obj2Bottom = obj2.offsetTop + obj2.offsetHeight - 5;
  var obj2Right = obj2.offsetLeft + obj2.offsetWidth;

  // Check to see if any of obj1's corners are inside obj2.
  if ((obj2Top < obj1Top && obj1Top < obj2Bottom) && (obj2Left < obj1Left && obj1Left < obj2Right))
      return true;

  if ((obj2Top < obj1Top && obj1Top < obj2Bottom) && (obj2Left < obj1Right && obj1Right < obj2Right))
      return true;

  if ((obj2Top < obj1Bottom && obj1Bottom < obj2Bottom) && (obj2Left < obj1Left && obj1Left < obj2Right))
      return true;

  if ((obj2Top < obj1Bottom &&obj1Bottom < obj2Bottom) && (obj2Left < obj1Right && obj1Right < obj2Right))
      return true;

  // Now check to see if any of obj2's corners are inside obj1.
  if ((obj1Top < obj2Top && obj2Top < obj1Bottom) && (obj1Left < obj2Left && obj2Left < obj1Right))
      return true;

  if ((obj1Top < obj2Top && obj2Top < obj1Bottom) && (obj1Left < obj2Right && obj2Right < obj1Right))
      return true;

  if ((obj1Top < obj2Bottom && obj2Bottom < obj1Bottom) && (obj1Left < obj2Left && obj2Left < obj1Right))
      return true;

  if ((obj1Top < obj2Bottom &&obj2Bottom < obj1Bottom) && (obj1Left < obj2Right && obj2Right < obj1Right))
      return true;

  // If you made it this far, congratulations! Your objects don't overlap!
  return false;
}

function doBasicDrag(event) {
  event = event || window.event;
  if (basicDragging && dragElement && !resizingPopupWindow) {
    var dObj = dragElement;
    var ft = document.getElementById("FixedTop");
    var ftHeight;
    if (ft) {
        ftHeight = ft.offsetHeight;
    } else {
        ftHeight = 0;
    }

    var pos = mouseCoords(event);

    var newTop = pos.y - mouseOffset.y;
    var newLeft = pos.x - mouseOffset.x;
    var newPreviewTop;
    var newPreviewLeft;

    if ( newTop < dragBoundaryTop ) {
      newTop = dragBoundaryTop;
    } else {
      windowHeight = getWindowHeight();
      if ( newTop > (windowHeight - 40) && !dragStep) {
        newTop = windowHeight - 40;
      }  
    }

    if (dragBoundaryTop != 0) {
      newTop -= ftHeight;
    }

    if (newLeft < dragBoundaryLeft ) {
      newLeft = dragBoundaryLeft;
    } else {
      windowWidth = getWindowWidth();
      if ( newLeft > (windowWidth - 40) && !dragStep) {
        newLeft = windowWidth - 40;
      }        
    }

    dObj.style.position = "absolute";
   
    yDelta = newTop % dragStep;
    if (yDelta == 0) {
      newSteppedTop = newTop;
    } else if (yDelta <= halfStep) {
      newSteppedTop = newTop - yDelta;
    } else {
      newSteppedTop = newTop + (dragStep - yDelta);
    }

    xDelta = newLeft % dragStep;
    if (xDelta == 0) {
      newSteppedLeft = newLeft;
    } else if (xDelta <= halfStep) {
      newSteppedLeft = newLeft - xDelta;
    } else {
      newSteppedLeft = newLeft + (dragStep - xDelta);
    }

    dObj.style.top = newSteppedTop;
    dObj.style.left = newSteppedLeft;

    for (var i = 0; i < draggingCallbacks.length; i++) {
      draggingCallbacks[i]();
    }

  } else if (resizingFolders) {
    var sc = document.getElementById("ScrollableContent");
    var ri = document.getElementById("ResizeIndicator");
    var x = getEventX(event);

    ri.style.height = sc.offsetHeight;
    ri.style.width = "1px";
    ri.style.visibility = "visible";
    ri.style.top = "0px";
    ri.style.left = x + "px";

    //hl.style.marginLeft = fl.offsetWidth;
    //mp.style.marginLeft = fl.offsetWidth;

    if (!ie) {
      document.body.style.MozUserSelect = "none";
      //this should be turn on again when dragging is completed using
      //document.body.style.MozUserSelect = "";
    } else if ( document.focusTrap ){
      document.focusTrap.focusTrap.focus();
    }
    
  } else if (resizingHeaders) {
    var sc = document.getElementById("ScrollableContent");
    var ri = document.getElementById("ResizeIndicator");
    var ft = document.getElementById("FixedTop");
    var y = getEventY(event) - ft.offsetHeight;

    ri.style.height = "1px";
    ri.style.width = sc.offsetWidth;
    ri.style.visibility = "visible";
    ri.style.top = y + "px";
    ri.style.left = "0px";
    
    //hl.style.height = y;
    if (!ie) {
      document.body.style.MozUserSelect = "none";
      //this should be turn on again when dragging is completed using
      //document.body.style.MozUserSelect = "";
    } else if ( document.focusTrap ) {
      document.focusTrap.focusTrap.focus();
    }
  }  
  return true;
}

function showPopup(popupId, popupAlign) {
  var popupObj = document.getElementById(popupId);
  if (popupObj && popupObj.style.display != "block") {
    jsPopupOpen += 1;
    popupObj.style.display = "block";

    if ( !popupWindows[popupId] || !popupWindows[popupId]["aligned"] ) {
      setPopupAlignment(popupObj, popupAlign);
    }
  }
  addZindex( popupObj )
  adjustJSPopup(popupId);
}
                    

function hidePopup(popupId) {
  var popupObj = document.getElementById(popupId);
  if (popupObj && popupObj.style.display == "block") {
    jsPopupOpen -= 1;
    popupObj.style.display = "none";
  }
}

function hideJSPopupOkButton(popupId) {
  var okObj = document.getElementById(popupId + "OKButton");
  if (okObj) {
    okObj.style.display = "none";
  }
}

function showJSPopupOkButton(popupId) {
  var okObj = document.getElementById(popupId + "OKButton");
  if (okObj) {
    okObj.style.display = "inline";
  }
}

function moveToCenter(objToMove) {
  var objHeight = objToMove.offsetHeight;
  var objWidth = objToMove.offsetWidth;

  pageBody = document.getElementById("ScrollableContent");
  var bodyHeight = pageBody.offsetHeight;
  var bodyWidth = pageBody.offsetWidth;

  objToMove.style.top = (bodyHeight / 2) - (objHeight / 2);
  objToMove.style.left = (bodyWidth / 2) - (objWidth / 2);
}

function checkPopSize( popName, minLen ) {
  var popObj = document.getElementById( popName ).style;
  var existLen = popObj.width;
  // remove px from end of existLen
  existLen = existLen.substr(0, (existLen.length-2) );
  if ( existLen < (minLen + 10 )  ) {
    popObj.width = minLen + 10;
  }
}

function ss_attachEvent(obj, eventStr, eventFunc) {
  if (obj.attachEvent) {
    // For IE
    obj.attachEvent("on" + eventStr, eventFunc);
  } else {
    // For Firefox
    obj.addEventListener(eventStr, eventFunc, false);
  }
}

function ss_detachEvent(obj, eventStr, eventFunc) {
  if (!obj) return;
  if (obj.detachEvent) {
    // For IE
    obj.detachEvent("on" + eventStr, eventFunc);
  } else {
    // For Firefox
    obj.removeEventListener(eventStr, eventFunc, false);
  }
}

function scheduleShowCompletions(event) {
  event = event || window.event;
  var tb = this;
  if (window.event && window.event.srcElement) {
    tb = window.event.srcElement;
  }

  var key = event.which || event.keyCode;

  var TAB = 9;
  var ENTER = 13;
  var ESC = 27;
  var UP = 38;
  var DOWN = 40;

  if (key != TAB && key != ENTER && key != ESC && (key < 35 || key > 40)) {
    // Keys 35 - 40 are arrow keys, home and end.
    clearTimeout(completionTimeout);
    completionTimeout = setTimeout(function() { showCompletions(tb, event) },
                                   500);
  }
  
  var cb = document.getElementById("CompletionBox");
  if (key == ESC) {
    hideCompletions(event);
  } else if (key == ENTER) {
    /* commented out as we don't want to change the field text by pushing enter button
    if (cb.style.display == "block" && cb.childNodes.length == 1) {
      if (tb.multi) {
        var values = tb.value.split(",");
        values[values.length - 1] = cb.firstChild.firstChild.nodeValue;
        tb.value = values.join(", ");
      } else {
        tb.value = cb.firstChild.firstChild.nodeValue;
      }
    } */
    hideCompletions(event);
  /*
  } else if (key == UP && cb.style.visibility == "visible") {
    if (selectedCompletion && selectedCompletion.previousSibling) {
      removeClassModifier("OverBg", selectedCompletion);
      doHighlightCompletion(selectedCompletion.previousSibling);
    }

    event.cancelBubble = true;
    if (event.stopPropagation) { event.stopPropagation(); }

  } else if (key == DOWN && cb.style.visibility == "visible") {
    if (!selectedCompletion) {
      doHighlightCompletion(cb.firstChild);
    } else if (selectedCompletion.nextSibling) {
      removeClassModifier("OverBg", selectedCompletion);
      doHighlightCompletion(selectedCompletion.nextSibling);
    }

    event.cancelBubble = true;
    if (event.stopPropagation) { event.stopPropagation(); }
    */
  }
}

function showCompletions(tb, event) {
  var cb = document.getElementById("CompletionBox");

  currentTB = tb;
  var valueToCheck = tb.value;

  if (tb.multi) {
    var values = valueToCheck.split(",");
    valueToCheck = values[values.length - 1];
    while (valueToCheck.length && valueToCheck.charAt(0) == " ") {
      valueToCheck = valueToCheck.slice(1);
    }
  }

  if (valueToCheck.length >= 2 && !completionLoading) {
    completionLoading = true;
    completionCall = AJAXRequest(getCompletions);
    makeAJAXCall(completionCall, 
                 tb.searchPylet + "?searchStr=" + valueToCheck,
                 true);
  } else {
    cb.style.display = "none";
  }
}

function getCompletions(data) {
  var cb = document.getElementById("CompletionBox");
  cb.innerHTML = "";
  cb.style.height = "";
  completionLoading = false;
  completionsFocused = false;


  if (data && data.completions && data.completions.length > 0 && currentTB.focused) {
    var completions = data.completions;

    var sc = document.getElementById("ScrollableContent");
    var cb = document.getElementById("CompletionBox");
    cb.selected = "";

    var left = 0;
    var top = 0;
      
    var el = currentTB;
    while (el.parentNode) {
      left += el.offsetLeft;
      if (el.nodeName != "TR") {
        // TD and TR have the same offset which throws off the calculation.
        top  += el.offsetTop
      }
      el = el.parentNode;
    }

    top -= completionOffset;
    left -= completionOffsetLeft;
    cb.style.left = left;
    cb.style.top = top + currentTB.offsetHeight - sc.scrollTop;
    cb.style.width = currentTB.offsetWidth;

    for (var i = 0; i < completions.length; i++) {
      var newDiv = document.createElement("div");
      var completion = document.createTextNode(completions[i]);
      newDiv.appendChild(completion);
      newDiv.style.overflow = "hidden";
      newDiv.style.whiteSpace = "nowrap";
      cb.appendChild(newDiv);
      ss_attachEvent(newDiv, "mouseover", highlightCompletion);
      ss_attachEvent(newDiv, "mouseout", blurCompletion);
    }
    cb.style.display = "block";
    if (cb.offsetHeight > 100) {
      cb.style.height = "10.5em";
      ss_attachEvent(cb, "scroll", setFocusedOnCompletions);
    }
  } else {
    cb.style.display = "none";
  }
  
}

function setFocusedOnCompletions() {
 var cb = document.getElementById("CompletionBox");
 completionsFocused = true;
 cb.focus();
}

function highlightCompletion(event) {
  event = event || window.event;
  var comp = this;
  if (window.event && window.event.srcElement) {
    comp = window.event.srcElement;
  }
  doHighlightCompletion(comp);

}

function doHighlightCompletion(completion) {
  var cb = document.getElementById("CompletionBox");
  cb.selected = completion.firstChild.nodeValue;
  selectedCompletion = completion;

  addClassModifier(completion, "OverBg");
}

function blurCompletion(event) {
  event = event || window.event;
  var comp = this;
  if (window.event && window.event.srcElement) {
    comp = window.event.srcElement;
  }
  var cb = document.getElementById("CompletionBox");
  cb.selected = "";  

  removeClassModifier(comp, "OverBg");
}

function setHideCompletions(event) {
  event = event || window.event;
  setTimeout( function() {hideCompletionsWithDelay(event)}, 300 );
}

function hideCompletionsWithDelay(ev) {
  if (!completionsFocused) hideCompletions(ev);
}

function hideCompletions(event) {
  var cb = document.getElementById("CompletionBox");
  if (cb) {
    cb.style.display = "none";
  }
}

function selectCompletions(event) {
  completionsFocused = true;
  var cb = document.getElementById("CompletionBox");
  if ( cb ) {
    cb.style.display = "none";
    if (cb.selected) {
      if (currentTB.multi) {
        var values = currentTB.value.split(",");
        values[values.length - 1] = cb.selected;
        currentTB.value = values.join(",");
      } else {
        currentTB.value = cb.selected;
      }
    }
  }  
}

function setFocused(event) {
  var tb = this;
  if (window.event && window.event.srcElement) {
    tb = window.event.srcElement;
  }

  tb.focused = true;
}

function findPos(obj)
{
 var left = !!obj.offsetLeft ? obj.offsetLeft : 0;
 var top = !!obj.offsetTop ? obj.offsetTop : 0;

 while(obj = obj.offsetParent)
 {
  left += !!obj.offsetLeft ? obj.offsetLeft : 0;
  top += !!obj.offsetTop ? obj.offsetTop : 0;
 }

 return top;
}

//Name Resolution Functions

function autoCompletionReset(ID){
      if ( !window['autoCompletionVar_' + ID] ) {
        return;
      }
      window['autoCompletionVar_' + ID].disable()
      window['autoCompletionVar_' + ID].enable()
      //this runs on focous
      //sets the proper width.  needed if the input startes out hidden
      var autoWidth = document.getElementById(ID).offsetWidth
      window['autoCompletionVar_' + ID].setOptions({ width: autoWidth })
      //sets the z-index so the autocomplete will work in div popups
      var newzIndex = popupHighZindex + 100
      window['autoCompletionVar_' + ID].setOptions({ zIndex: newzIndex })
    }
  
function addAutoCompletion(textbox, searchType, nameCompletion) {
  var options
  var objID = "#" + textbox.id

  // sets up onfocous functions that fix various issues
  if (nameCompletion == true){  
 
      textbox.onfocus = function(){ autoCompletionReset(textbox.id) }
      var pylet = getProperUrl("templates", "ajax_completion.pyt")
      var noCache = false
      var params = { searchType: searchType }
  }
  else{

      var pylet = getProperUrl("webmail", "ajax_search_completion.pyt")
      var noCache = true
      var params = { searchType: searchType,
                     folderPath: "INBOX"}
  }

  // initialises the autocomplete
  jQuery(function(){

        options = { serviceUrl: pylet,
                    delimiter: /(,|;)\s*/,
                    maxHeight: 200,
                    noCache: noCache,
                    params: params,
                    fnFormatResult: function(value, data, currentValue){
                                              var reEscape = new RegExp('(\\' + ['/', '<', '>', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\'].join('|\\') + ')', 'g');
                                              if (currentValue == "l"   || currentValue == "t"   || currentValue == "&l"  || currentValue == "lt"   || 
                                                  currentValue == "t;"  || currentValue == "&lt" || currentValue == "lt;" || currentValue == "&lt;" || 
                                                  currentValue == "g"   || currentValue == "t"   || currentValue == "&g"  || currentValue == "gt"   ||
                                                  currentValue == "t;"  || currentValue == "&gt" || currentValue == "gt;" || currentValue == "&gt;"){
                                                    value = value.replace("<","&#60;")
                                                    value = value.replace(">","&#62;")
                                                  }
                                              else{
                                                  value = value.replace("<","&lt;")
                                                  value = value.replace(">","&gt;")
                                                  }
                                              var pattern = '(' + currentValue.replace(reEscape, '\\$1') + ')';
                                              return value.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
                                              
                                            }
      }
    //this creates dynamic variables
    window['autoCompletionVar_' + textbox.id] = $(objID).autocomplete(options);
  });

}
 
// Date Picker Functions

function datepicker_backendSet(dateArray, dateFormat, backendStyle, backendId, backendYearId, backendMonthId, backendDayId){
    // this function is used to set the inputs that are used for the backend
    if (backendStyle == "3" || backendStyle == "both"){
        //old style, 3 inputs
        document.getElementById(backendYearId).value = dateArray[2]
        document.getElementById(backendMonthId).value = dateArray[0] 
        document.getElementById(backendDayId).value = dateArray[1]
    }
    if (backendStyle != "3"){
        //new style, onr input
        document.getElementById(backendId).value = dateFormat
    }
}

function setDatepickerDate(id,date){

  if(typeof(date) == 'object'){
      dateArray = date
  }else{
      dateArray = datepickerDateCalculation(date)
  }

  var dateStr  = dateArray[1] + "/" + dateArray[2] + "/" + dateArray[0]
  document.getElementById(id).value = dateStr
}

function showCalendar(id){
  var jID = "#" + id

  if (typeof(datePickerInput) != 'undefined' && datePickerInput == id){
     if (datePickerState == "closed"){
        $(jID).datepicker( "show" );
        datePickerState = "open"
     }else{
        $(jID).datepicker( "hide" );
        datePickerState = "closed"
     }
  } else{
    datePickerInput = id
    $(jID).datepicker( "show" );
    datePickerState = "closed"
  }
}

function calculateOffset(offset){
  var datepicker_bottomLocation = offset.top + document.getElementById("ui-datepicker-div").offsetHeight
  var datepicker_topLocation    = offset.top - 19 - document.getElementById("ui-datepicker-div").offsetHeight
  var pageHeight                = getPageHeight()
  
  if (datepicker_bottomLocation >= getPageHeight()){
      offset.top = offset.top - document.getElementById("ui-datepicker-div").offsetHeight - 19
     }
  
  return offset;
}

function changeScreenSize(w,h){
   {
     window.resizeTo( w,h )
   }
}
function getPageHeight(){
    if (self.innerHeight){
          pageHeight = self.innerHeight;
    }else if (document.documentElement && document.documentElement.clientHeight){
          pageHeight = document.documentElement.clientHeight;
    }else if (document.body){
          pageHeight = document.body.clientHeight;
    }
    return pageHeight;
}

function beforeShowDatepickerFunc(input){
    if (input.value == ""){
        $(input).datepicker( "setDate" , getCurentDate("/") )
    }
    datePickerInput = input.id
    datePickerState = "open"
}

function getCurentDate(delimiter){
    if (typeof(delimiter) == 'undefined'){
       delimiter = "/"
    }
   
    currentTime = new Date()
    month = currentTime.getMonth() + 1
    day = currentTime.getDate()
    year = currentTime.getFullYear()

    todaysDate = month + delimiter + day + delimiter + year
    return todaysDate;
}

function setDatePickerToToday(input){
    $(input).datepicker( "setDate" , getCurentDate("/") )
    $(input).datepicker( "hide" )
}

function keyFunc(e) {
   return e.keyCode? e.keyCode : e.charCode
   }
      
function datepickerInput_onKeyUpFunc(e, id){
  keyValue = keyFunc(e)
  jID = "#" + id
  if (keyValue == 8 || keyValue == 46){
      $(jID).datepicker( "hide" )
      funcName = "clearDatepicker_" + id + "()"
      eval(funcName)
  }
}

function datepickerDateCalculation(date){
  
  //if their is a space in the string after the date, remove the space and 
  //everything after it.  This is needed becasue sometimes the time is
  //appended to the end of the string
  
  if(date.search(" ") != -1){
      date = date.split(" ")[0]
  }
  
  //check to make sure the string that is passed was not empty
  //and containsthe neesesary parts ot be considerd a readable date
  
  var charNumTest = new RegExp( "^(?=.*[A-Z])(?=.*[a-z]).*$", "g" );
  
  if(date == "" || charNumTest.test(date)){
    return false;
  }

  var dateArray = new Array();

  //Detect if the date string is one of the three date types that are 
  //supported, yyyy-mm-dd, and mm/dd/yyyy
  
  backendDateType  = new RegExp( "[0-9]{4}-[0-9]{2}-[0-9]{2}", "g" );
  standardDateType = new RegExp( "([0-9]|[0-9]{2})\/([0-9]|[0-9]{2})\/[0-9]{4}", "g" );
  
  if(backendDateType.test(date)){
      dateArray = date.split('-')
  }else if(standardDateLong.test(date)){
      var tempArray = date.split('/')
      
      if (tempArray[0].length == 1){
         tempArray[0] = '0' + tempArray[0]
      }
      if (tempArray[1].length == 1){
         tempArray[1] = '0' + tempArray[1]
      }
      
      dateArray[0] = tempArray[2]
      dateArray[1] = tempArray[0]
      dateArray[2] = tempArray[1]
  }else{
    return false
  }
  
  //check to make sure that all dates are actuall numbers, and not 00 or 0000
  
  for (x=0; x<=2; x++){
    if(dateArray[x] == "" || dateArray[x] - 0 == 0){
       return false
    }
  }

  //check to make sure that the number of days is ok for the month
  
  var maxMonth = 0;
  var day   = dateArray[2] - 0
  var month = dateArray[1] - 0;
  var year  = dateArray[0] - 0;
  
  if  (month==1 || month==3 || month==5 || month==7 || month==8 || month==10 || month==12){
      maxMonth = 31
  }else if(month==4 || month==6 || month==9 || month==11){
      maxMonth = 30
  }else if(month == 2 && year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)){
      maxMonth = 29
  }else if(month == 2){
      maxMonth = 28
  }else{
      return false
  }
  
  if(day> maxMonth){
      return false
  }

  return dateArray
  
}

// password meter functions

function checkPasswordStrength(passowrdArray, noAlert){

  var pwordError = 0
  var pwordNotMatch = 0
  var pwordTooLong = 0
  if (typeof(passowrdArray) != 'undefined'){
      for (x=2; x < passowrdArray.length; x++){
          
          confirmArrayName = passowrdArray[x][0] + '_ConfirmArray'
          confirmPasswordStatus = passwordReEnterCheck(window[confirmArrayName])
          if (parseInt(passowrdArray[x][1]) < parseInt(passowrdArray[0])){
              pwordError = 1
          }
          if (confirmPasswordStatus != 1){
              pwordNotMatch = 1
          }
          if (passowrdArray[x][1] >= 4){
              pwordTooLong = 1
          }
        }
      }

  if (pwordError == 1){
  
      var alertStr = "Your password does not meet the security standards.  All passwords must contain at least <b>" + passowrdArray[1] + "</b> characters"
      
      if (passowrdArray[0] == 0){
         alertStr  = "Please enter a password"
      }else if (passowrdArray[0] == 1){
         alertStr += "and be rated <b>weak</b> by including at least one of the following"
      }else if(passowrdArray[0] == 2){
         alertStr += " and be rated <b>medium</b> by including at least two of the following:\n\n"
      }else if(passowrdArray[0] == 3){
         alertStr += " and be rated <b>strong</b> by including all of the following:\n\n"
      }
      
      if (passowrdArray[1] > 1){
          alertStr +="<ul>"
          alertStr +="<li>A capital letter <b>(ABC)</b></li>"
          alertStr +="<li>A lower-case letter <b>(abc)</b></li>"
          alertStr +="<li>A number <b>(1-9)</b></li>"
          alertStr +="<li>A symbol <b>(@*!)</b></li>"
          alertStr +="<ul>"
      }
  }else if (pwordNotMatch == 1){
     var alertStr = "The Password field and the Confirm Password field must match."
  }else if(pwordTooLong == 1){
     var alertStr = "The maximum password length is 64 characters"
  }

  if (typeof(alertStr) == 'undefined'){
     return true
  } else{
     if (!noAlert){
         document.getElementById("passwordMeterInnerPopupContent").innerHTML = alertStr
         showPopup("passwordMeterPopup")
         return false
    }else{
    return alertStr
    }
  }
  
}

function passwordStrength( pwd, minPwdLen ) {

  var lowerRegex = new RegExp( "^(?=.*[A-Z]).*$", "g" );
  var upperRegex = new RegExp( "^(?=.*[a-z]).*$", "g" );
  var numRegex   = new RegExp( "^(?=.*[0-9]).*$", "g" );
  var specRegex  = new RegExp( "^(?=.*[\w\.!#$%^%&*_+=|;:',<>?~@-]).*$", "g" );
  
  var strength   = 0
  var tempLenAdd = 0
  
  if (lowerRegex.test(pwd)){
      strength += 2
  }
  if (upperRegex.test(pwd)){
      strength += 2
  }
  if (numRegex.test(pwd)){
      strength += 2
  }
  if (specRegex.test(pwd)){
      strength += 2
  }
  
  if (pwd.length < minPwdLen){
     tempLenAdd += (pwd.length / minPwdLen) * 6
     if (tempLenAdd > 6){
          tempLenAdd = 6        
        }
  }else if ( pwd.length > 64){
    strength = 65
  }else {
        if (strength < 4){
            tempLenAdd = pwd.length - 4
            if (tempLenAdd > 2){
               tempLenAdd = 2
            }
        } else if (strength >= 4 ){
            tempLenAdd = pwd.length - 4
            if (tempLenAdd > 4){
               tempLenAdd = 4
            }
        if (strength >= 8){
            strength += 4;
          }
        }
      strength += 6
  }

  strength += tempLenAdd
  return strength;
}

function generatePasswordConfirmElements(){
   for (x = 0; x < passwordConfirmArray.length; x++){
   
    var pwdchk       = document.getElementById(passwordConfirmArray[x][1])
    var pwdchkParent = pwdchk.parentNode
    var pwdchkSpan   = document.createElement('span');
   
   
    if (passwordConfirmArray[x][4] == 'table' && passwordConfirmArray[x][3] != "skipCreate"){

        var passwordConfirmErrorCell = document.createElement('td');
        passwordConfirmErrorCell.setAttribute('style', 'margin: 0px; padding: 2px; display: none;');
        passwordConfirmErrorCell.setAttribute('id', passwordConfirmArray[x][2]);
        passwordConfirmErrorCell.setAttribute('name', passwordConfirmArray[x][2]);
        
        var passwordConfirmInputCell = document.createElement('td');
        passwordConfirmInputCell.setAttribute('style', 'margin: 0px; padding: 0px; width:100%;');

        var passwordConfirmRow = document.createElement('tr');
        passwordConfirmRow.setAttribute('style', 'margin: 0px; padding: 0px;');
        passwordConfirmRow.appendChild(passwordConfirmInputCell)
        passwordConfirmRow.appendChild(passwordConfirmErrorCell)
        
        var passwordConfirmTable = document.createElement('table');
        passwordConfirmTable.setAttribute('style', 'margin: 0px; padding: 0px; border-width: 0px; border-spacing: 0px; width:100%;');
        passwordConfirmTable.appendChild(passwordConfirmRow)
        
        pwdchkParent.insertBefore(passwordConfirmTable,pwdchk);
        pwdchkParent.removeChild(pwdchk)

        passwordConfirmInputCell.appendChild(pwdchk)
        pwdchk.setAttribute('style', 'width:100%');
        
    } else if (passwordConfirmArray[x][3] != "skipCreate"){
        pwdchkSpan.setAttribute('id', passwordConfirmArray[x][2]);
        pwdchkSpan.style.padding = '2px' 
        pwdchkSpan.innerHTML = " "
        pwdchkParent.appendChild(pwdchkSpan)
    }
    
    var arrayName = passwordConfirmArray[x][0] + '_ConfirmArray'
    
    window[arrayName] = new Array();
    window[arrayName][0] = passwordConfirmArray[x][0]
    window[arrayName][1] = passwordConfirmArray[x][1]
    window[arrayName][2] = passwordConfirmArray[x][2]
    
    if (passwordConfirmArray[x][3] == "skipCreate"){
        window[arrayName][3] = passwordConfirmArray[x][3]
    }
    
    var keyupfunc = 'passwordReEnterCheck( ' + arrayName + ' )'

    pwdchk.setAttribute('onblur', keyupfunc);
   }
}

function passwordReEnterCheck(arrayName, emptyCheck){

  var source = document.getElementById(arrayName[0])
  var check  = document.getElementById(arrayName[1])
  var span   = document.getElementById(arrayName[2])
  
  passwordArrayNumSpec = arrayName[0] + 'ArrayNum'
  if (check.value == "" && !emptyCheck){
      if(arrayName[3] == "skipCreate"){
         if(span.nodeName == "TD"){
            var spanRow = span.parentNode
            spanRow.style.display = 'none'
         }else{
          span.style.display = "none"
         }
         span.innerHTML = ""
      }else{
         if(span.nodeName == "TD"){
            span.style.display = 'none'
         }
        span.innerHTML = ""
      }
      passowrdArray[window[passwordArrayNumSpec]][2] = 0
      return 0
  }else if (check.value == source.value && !emptyCheck){
      if(arrayName[3] == "skipCreate" && span.innerHTML!=""){
          if(span.nodeName == "TD"){
            var spanRow = span.parentNode
            spanRow.style.display = 'none'
          }else{
           span.style.display = "none"
          }
          span.innerHTML = ""
      }else if(arrayName[3] != "skipCreate"){
         if(span.nodeName == "TD"){
            span.style.display = 'none'
         }
        span.innerHTML = ""

      }
      passowrdArray[window[passwordArrayNumSpec]][2] = 1
      return 1
  }else if(!emptyCheck){
      span.innerHTML = "<nobr>Passwords do not match</nobr>"
      passowrdArray[window[passwordArrayNumSpec]][2] = 0
      if(arrayName[3] == "skipCreate"){
        if(span.nodeName == "TD"){
          var spanRow = span.parentNode
          if(ie){
            spanRow.style.display = 'block'
          }else{
            span.style.display    = 'table-cell' 
            spanRow.style.display = 'table-row'
          }
        }else{
          span.style.display = "block"
        }
      }else{
        if(span.nodeName == "TD"){
            span.style.display = 'table-cell'
        }else{
          span.style.display = "block"
        }
      }
      return 0
  }
  return 0
}

function getBarLength(strength){
    var barLen = (strength/22)* 100
    barLen += "%"
    return barLen
}

//inline Alert Functions



function indexOf(array, value) {
  for (var idx = 0; idx < array.length; idx++) {
    if (array[idx] == value) {
      return idx;
    }
  }

  return -1;
}

function ss_showConsole() {
  showPopup("SS_Console");
}

function ss_hideConsole() {
  hidePopup("SS_Console");
}

function ss_writeToConsole(message) {
  var now = new Date();
  var console = document.getElementById("SS_ConsoleData");

  dateStr = "<b>" + now.toGMTString() + " - </b>";
  console.innerHTML += dateStr + message + "<br/>";
  console.scrollTop = console.scrollHeight;
  ss_showConsole();
}

function ss_clearConsole() {
  var console = document.getElementById("SS_ConsoleData");
  console.innerHTML = "";
}

/*
 * Remove Re, RE, Fwd or FWD from the begining of a string
 * used for Ajax mail, soting by subject
 */
function clearSubject( orderByVal ) {
  var re = new RegExp(/^re:|^fwd:|^\[fwd:|^ |^\[[a-z,-]*\]/);
  while ( re.test(orderByVal) ) {
    orderByVal = orderByVal.substr( (re.exec(orderByVal) + "").length );
  }    
  return orderByVal;
}

function insertItemToArray( arr, val, pos ) {
  if(pos || pos == 0) {
    partB = arr.splice(pos, (arr.length-pos));
    arr.push(val);
    arr = arr.concat(partB);
  } else {
    arr.push(val);
  }

  return arr;
}

// ####### tree.js #######
// Functions for the drawing of folder trees.

var defaultClosed;
var defaultOpen;
var lastOpenedTreeRow;
var treeDragging;
var treeData = new Object;
var treeDroppables = new Array;
var unreadNumbers = 0;
var treeDataUpdated = false;

var treeFunctions = {
  functions: new Object,
  setSingleClick: function(callback) {
    this.functions["SINGLE"] = callback;
  },
  setDoubleClick: function(callback) {
    this.functions["DOUBLE"] = callback;
  },
  setOnOpen: function(callback) {
    this.functions["ONOPEN"] = callback;
  },
  setOnClose: function(callback) {
    this.functions["ONCLOSE"] = callback;
  },
  doFunction: function(type, row) {
    var callback = this.functions[type];
    if (callback) {
      callback(row);
    }
  }
}

function drawTree(data, container) {
  if (!data) {
    return;
  }  
  if (data.length == undefined) {
    drawTreeRoot(data, container);
  } else {
    for (var i = 0; i < data.length; i++) {
      drawTreeRoot(data[i], container);
    }
  }
}

function drawTreeRoot(data, container) {
  treeData[data["id"]] = data;
  var childCount = 0;
  if (data["subFolders"]) {
    childCount = data["subFolders"].length;
    if (childCount == undefined) {
      childCount = 1;
    }
  }
  var subContainer = drawTreeRow(data["id"], data["name"], container,
                                 data["description"], data["folderIcon"],
                                 childCount, "", data["folderIconWidth"],
                                 data["folderIconHeight"]);

  function doSubFolders(subNode, subContainer) {
    if (subNode["subFolders"] == undefined) {
      return;
    } else if (!subNode["subFolders"].length) {
      subNode["subFolders"] = new Array(subNode["subFolders"]);
    }

    for (var i = 0; i < subNode["subFolders"].length; i++) {
      var row = subNode["subFolders"][i];
      var childCount = 0;
      
      if (row["subFolders"] != undefined) {
        if (row["subFolders"].length == undefined) {
          row["subFolders"] = new Array(row["subFolders"]);
        }
        childCount = row["subFolders"].length;
      }
      treeData[row["id"]] = row;
      
      var subSubContainer = drawTreeRow(row["id"], row["name"], subContainer,
                                        row["description"], row["folderIcon"],
                                        childCount, "", row["folderIconWidth"],
                                        row["folderIconHeight"]);

      if (row["subFolders"] && row["subFolders"].length > 0) {
        doSubFolders(row, subSubContainer);
      }
    }
  }

  doSubFolders(data, subContainer);
}

function drawTreeRow(id, name, parent, description, icon, hasChildren, nextFolderObj, iconWidth, iconHeight) {
  defaultClosed = imagesURL + "/iconset/ss_small_folder_closed.png";
  defaultOpen = imagesURL + "/iconset/ss_small_folder_open.png";

  if (!icon) { 
    icon = defaultClosed;
    iconWidth = 16;
    iconHeight = 15;
  } else if (icon.indexOf("http") == 0) {
    icon = icon;
  } else {
    icon = imagesURL + icon;
  };

  var container = document.createElement("div");
  container.id = id + "_Container";
  container.rowId = id;
  container.className = "FolderRow";
  container.onmouseover = highlightTreeRow;
  container.onmouseout = unhighlightTreeRow;
  //container.onclick = treeRowClicked;
 
  var newImg = document.createElement("img");
  newImg.childCount = hasChildren;
  if (hasChildren) {
    newImg.src = imagesURL + "/iconset/ss_widget_expand.png";
    newImg.onclick = expandTreeRow;
    newImg.width = 16;
    newImg.height = 16;
  } else {
    newImg.src = imagesURL + "/filemanager/ftv2blank.gif";
    newImg.width = 16;
    newImg.height = 22;
  }
  newImg.style.verticalAlign = "bottom";
  container.appendChild(newImg);

  var folderImgSpan = document.createElement("span");
  var newImg = document.createElement("img");
  newImg.src = icon;
  if (iconWidth) {
    newImg.width = iconWidth;
  }
  if (iconHeight) {
    newImg.height = iconHeight;
  }
  newImg.closedIcon = icon; // For opening/closing.
  folderImgSpan.className = "FolderIcon";
  folderImgSpan.onclick = selectTreeFolder;

  folderImgSpan.appendChild(newImg);
  container.appendChild(folderImgSpan); 

  folderNameSpan = document.createElement("span");
  folderNameSpan.id = id + "_Name";
  folderNameSpan.className = "FolderName";
  tn = addText(name, folderNameSpan);
  folderImgSpan.appendChild(folderNameSpan);

  if (description && description != "") {
    tn.tipId = id + "Tip";
    if (tn.attachEvent) {
      // For IE
      tn.attachEvent("onmouseover", openGenericTip);
    } else {
      // For Firefox
      tn.addEventListener("mouseover", openGenericTip, false);
    }
    tn.onmouseout = closeGenericTip;
    createToolTip(tn.tipId, description);
  }

  if( nextFolderObj ) {
    parent.insertBefore( container, nextFolderObj );
  } else {
    parent.appendChild(container);
  }

  treeDroppables.push(container);

  var subContainer = document.createElement("div");
  subContainer.id = id + "_Contents";
  subContainer.folderId = id;
  subContainer.className = "FolderContents";
  subContainer.style.display = "none";

  if (nextFolderObj) {
    parent.insertBefore( subContainer, nextFolderObj );
  } else {
    parent.appendChild(subContainer);
  }  
  return subContainer;
}

function boldTreeRows(data, repeat) {
  var folderList = data.unread_count;
  if (folderList) {
    if (!folderList.push) {
      folderList = new Array(folderList);
    }

    for (var i = 0; i < folderList.length; i++) {
      var folderData = folderList[i];
      var id = folderData["path"];
      if ( id != lastOpenedTreeRow ) {
        var folderName = document.getElementById(id + "_Name");
        if ( folderName ) {
          var folderContents = document.getElementById(id + "_Contents");
          if (folderData.unseen > 0 ) {
            addClassModifier(folderName, "Unread");
            folderName.firstChild.innerHTML = folderData["name"] + " (" + folderData.unseen + ")";
            boldParents(folderContents);
          } else {
            removeClassModifier(folderName, "Unread");
            folderName.firstChild.innerHTML = folderData["name"];
          }
        } else if (!repeat) {
          // it is possible that folder tree is not loaded yet so call this fuction after 2 sec again.
          setTimeout( function() {boldTreeRows(data, 1)}, 2000 );
          break;
        }
      }  
    }
  }
}
  
function boldParents(child) {
  var parent = child.parentNode;
  if ( !parent || parent.style.display == "block" ) {
    return;
  } else {
    var parentName = document.getElementById(parent.folderId + "_Name");
    if (parentName && parentName.className.indexOf("Unread") == -1) {
      addClassModifier(parentName, "Unread");
    }  
    if ( parent.folderId && parent.folderId != "INBOX" ) {
      boldParents(parent);
    }
  }
}

function folderHasUnread(folderId) {
  var hasUnread = false;

  var folderName = document.getElementById(folderId + "_Name");
  var folderData = treeData[folderId];

  if (!folderName || folderName.className.indexOf("Unread") > -1) {
    return true;
  }

  if (folderData.subFolders) {
    for (var i = 0; i < folderData.subFolders.length; i++) {
      var subFolderPath = folderId + "." + folderData.subFolders[i].name;
      hasUnread = folderHasUnread(subFolderPath);
      if (hasUnread) {
        return hasUnread;
      }
    }
  }

  return hasUnread;
}

function selectTreeFolder() {
  openTreeFolder(this.parentNode.rowId);
}

function expandTreeRow() {
  toggleRowState(this.parentNode, true);
}

function toggleRowState(folderRow, noClick) {
  var rowData = treeData[folderRow.rowId];
  var contents = folderRow.nextSibling;
  var name = document.getElementById(folderRow.rowId + "_Name");
  bulletImg = folderRow.firstChild;
  folderImg = bulletImg.nextSibling;

  if (!noClick) {
    treeFunctions.doFunction("SINGLE", rowData);
  }

  if (contents.style.display == "none") {
    if (folderImg.src == defaultClosed) {
      folderImg.src = defaultOpen;
    }
    if (bulletImg.childCount) {
      bulletImg.src = imagesURL + "/iconset/ss_widget_contract.png";
    }
    contents.style.display = "block";
    treeFunctions.doFunction("ONOPEN", rowData);
    if ( (name.firstChild.innerHTML).indexOf("(") == -1) {
      removeClassModifier(name, "Unread");
    }
  } else {
    if (folderImg.src == defaultOpen) {
      folderImg.src = defaultClosed;
    }
    if (bulletImg.childCount) {
      bulletImg.src = imagesURL + "/iconset/ss_widget_expand.png";
    }
    contents.style.display = "none";
    treeFunctions.doFunction("ONCLOSE", rowData);
    if (folderHasUnread(folderRow.rowId)) {
      addClassModifier(name, "Unread");
    }
  }
}

function openGenericTip(event) {
  if (window.event && window.event.srcElement) {
    showTip(window.event.srcElement.tipId, event);
  } else {
    showTip(this.tipId, event);
  }
}

function closeGenericTip(event) {
  if (window.event && window.event.srcElement) {
    hideTip(window.event.srcElement.tipId);
  } else {
    hideTip(this.tipId);
  }
}

function toggleFolder(folderId, noClick) {
  var folderRow = document.getElementById(folderId + "_Container");
  var folderContents = document.getElementById(folderId + "_Contents");

  var openFolder = false;
  if (folderContents.style.display == "none") {
    openFolder = true;
  }

  if (folderRow) {
    toggleRowState(folderRow, noClick);
  }

  var done = false;
  if (openFolder) {
    do {
      rowParent = folderRow.parentNode;
      if (rowParent.className != "FolderContents") {
        done = true;
        break;
      } else {
        folderRow = rowParent.previousSibling;
        if (rowParent.style.display == "none") {
          toggleRowState(folderRow, true);
        }
      }
    } while (!done);
  }
}

function openTreeFolder(folderId, noClick, noSelect) {
  var folderContents = document.getElementById(folderId + "_Contents");
  var folderName = document.getElementById(folderId + "_Name");

  if (!folderContents) {
    return;
  }

  if (folderContents.style.display == "none") {
    toggleFolder(folderId, noClick);
    removeClassModifier(folderName, "Unread");
  } else {
    var rowData = treeData[folderId];

    if (!noClick) {
      treeFunctions.doFunction("SINGLE", rowData);
    }
  }

  if (!noSelect) {
    if (lastOpenedTreeRow) {
      unselectTreeRow(lastOpenedTreeRow);
    }

    selectTreeRow(folderId);
    lastOpenedTreeRow = folderId;
  }
}

function closeTreeFolder(folderId, noClick) {
  var folderContents = document.getElementById(folderId + "_Contents");
  var folderName = document.getElementById(folderId + "_Name");

  if (folderContents.style.display == "block") {
    toggleFolder(folderId, noClick);
    if (folderHasUnread(folderId)) {
      addClassModifier(folderName, "Unread");
    }
  }
}

function highlightTreeRow(event) {
  if (window.event && window.event.srcElement) {
    var target = window.event.srcElement;
    while (target.nodeName != "DIV") {
      target = target.parentNode;
    }
    var treeRow = target;
  } else {
    var treeRow = this;
  }

  if (treeRow.lastChild.nodeName == "#text") {
    addClassModifier(treeRow.lastChild, "OverBg");
  } else {
    addClassModifier(treeRow.lastChild.lastChild, "OverBg");
  }
}

function unhighlightTreeRow(event) {
  if (window.event && window.event.srcElement) {
    var target = window.event.srcElement;
    while (target.nodeName != "DIV") {
      target = target.parentNode;
    }
    var treeRow = target;

  } else {
    var treeRow = this;
  }

  if (treeRow.lastChild.nodeName == "#text") {
    removeClassModifier(treeRow.lastChild, "OverBg");
  } else {
    removeClassModifier(treeRow.lastChild.lastChild, "OverBg");
  }
}

function selectTreeRow(folderId) {
  var folderName = document.getElementById(folderId + "_Name");
  removeClassModifier(folderName, "OverBg");
  addClassModifier(folderName, "SelectedBg");
}

function unselectTreeRow(folderId) {
  var folderName = document.getElementById(folderId + "_Name");
  if (folderName) {
    removeClassModifier(folderName, "SelectedBg");
    removeClassModifier(folderName, "SelectedInactiveBg");
  }
}

function dropOnTree(event) {
  //needs custom code for each application
  if (listDragging) {
    alert("You're moving a list");
  } else if (treeDragging) {
    alert("You're moving a folder");
  } else {
    alert("You weren't dragging!!???!");
  }

  return false;
}


function messagesDropped(data) {
  //needs custom code for each application
}

function wmCallStatus(data) {
  if (data["errors"]) {
    alert(data["errors"]);
  }
}

function getRowUnderCursor(event) {
  var folderTree = document.getElementById("FolderTree");
  var ft = document.getElementById("FixedTop");
  var ftHeight = ft.offsetHeight;

  if (folderTree.style.top) {
    ftHeight += Number( removePX(folderTree.style.top) );
  }

  var x = getEventX(event);
  var y = getEventY(event) - ftHeight;
  for (var i = 0; i < treeDroppables.length; i++) {
    var folderRow = treeDroppables[i];
    if (((folderRow.offsetTop - folderTree.scrollTop)) < y && y < ((folderRow.offsetTop + folderRow.offsetHeight - folderTree.scrollTop)) && (folderRow.offsetLeft < x && x < (folderRow.offsetLeft + folderRow.offsetWidth))) {
      return folderRow;
    }
  }
}

function insertTreeRow(newFolderName, parentId, useSlash) {
  var destContainer = document.getElementById(parentId + "_Contents");
  var destFolderRow = document.getElementById(parentId + "_Container");
  if(useSlash) {
    if (parentId == "/") {
      var newFolderId = "/" + newFolderName;
    } else {
      var newFolderId = parentId + "/" + newFolderName;
    }  
  } else {
    var newFolderId = parentId + "." + newFolderName;
  }   

  var newFolderObj = new Object();
  newFolderObj.id = newFolderId;
  newFolderObj.name = newFolderName;

  var parentFolderObj = treeData[parentId];
  if (parentFolderObj.subFolders) {
    nextFolderObj = getNextFolder ( parentFolderObj.subFolders, newFolderName, parentId);
    parentFolderObj.subFolders = insertItemToArray(parentFolderObj.subFolders, newFolderObj, nextFolderObj.pos );
  } else {
    parentFolderObj.subFolders = new Array(newFolderObj);
    var widgetImg = destFolderRow.firstChild;
    if( destContainer.style.display == "block") {
      widgetImg.src = imagesURL + "/iconset/ss_widget_contract.png";
    } else {
      widgetImg.src = imagesURL + "/iconset/ss_widget_expand.png";
    }
    widgetImg.width = 16;
    widgetImg.height = 16;
    widgetImg.onclick = expandTreeRow;
    widgetImg.childCount = 1;
    nextFolderObj = false;
  }
  drawTreeRow(newFolderId, newFolderName, destContainer, "", "", "", nextFolderObj);
  treeData[newFolderId] = newFolderObj
  treeDataUpdated = true;
}

function deleteTreeRow(rowId, useSlash) {
  var treeRow = document.getElementById(rowId + "_Container");
  var treeRowContents = document.getElementById(rowId + "_Contents");

  if (useSlash) {
    var parentId = rowId.substr(0, rowId.lastIndexOf("/") ); 
    if (!parentId) {
      parentId = "/";
    }
  } else {
    var parentId = rowId.substr(0, rowId.lastIndexOf(".") ); 
  }

  var parentFolderRow = document.getElementById(parentId + "_Container");
  var parentFolderObj = treeData[parentId];

  delete treeData[rowId];
  treeDataUpdated = true;
  treeRow.parentNode.removeChild(treeRow);
  treeRowContents.parentNode.removeChild(treeRowContents);

  pos = "";
  for ( i=0; i<parentFolderObj.subFolders.length; i++ ) {
    folderObj = parentFolderObj.subFolders[i];
    if ( folderObj.id == rowId ) {
      pos = i;
      break;
    }
  }
  parentFolderObj.subFolders.splice(pos,1);
  if (parentFolderObj.subFolders.length == 0 ) {
    parentFolderObj.subFolders = "";
    var widgetImg = parentFolderRow.firstChild;
    widgetImg.src = imagesURL + "/filemanager/ftv2blank.gif";
    widgetImg.onclick = null;
    widgetImg.childCount = 0;

  }
}

function copyTreeRow(rowId, destId) {
  rowId = rowId.replace(/\\\//g, "/");
  var lastSlashPos = rowId.lastIndexOf("/");
  var folderName = rowId.substr( lastSlashPos + 1 );

  insertTreeRow( folderName, destId, true);

  var treeObj = treeData[rowId];   
  if (treeObj.subFolders) {
    for ( k in treeObj.subFolders) {
      if (destId == "/") {
        var newDestId = "/" + folderName;
      } else {
        var newDestId = destId + "/" + folderName; 
      }      
      copyTreeRow( treeObj.subFolders[k].id, newDestId );
    }
  }
}


function moveTreeRow(rowId, destId, uesSlash) {
  rowId = rowId.replace(/\\\//g, "/");   
  copyTreeRow( rowId, destId );
  deleteTreeRow(rowId, uesSlash);
}

function renameTreeRow(newFolderName, oldId, uesSlash) {
  var targetRow = document.getElementById(oldId + "_Container");
  var targetContents = document.getElementById(oldId + "_Contents");
  var targetNameObj = document.getElementById(oldId + "_Name");

  if (uesSlash) {
    var separator = "/";
  } else {
    var separator = ".";
  }  

  var folderStruct = oldId.split(separator);
  var oldFolderName = folderStruct.pop();
  if (folderStruct.length) {
    var parentId = folderStruct.join(separator);
  } else {
    var parentId = false;
  }

  folderStruct.push(newFolderName);
  var newId = folderStruct.join(separator);

  targetRow.rowId = newId;
  targetRow.id = newId + "_Container";
  targetNameObj.firstChild.innerHTML = newFolderName;
  targetNameObj.id = newId + "_Name";
  targetContents.id = newId + "_Contents";

  lastOpenedTreeRow = newId;

  var rowData = treeData[oldId];
  treeData[newId] = rowData;
  treeDataUpdated = true;
  treeData[oldId] = undefined;

  if (parentId) {
    var parentData = treeData[parentId];
    for (var i = 0; i < parentData.subFolders.length; i++) {
      var childData = parentData.subFolders[i];
      if (childData.id == oldId) {
        childData.id = newId;
        childData.name = newFolderName;
        if (childData.subFolders){
          changeChildrenIds(childData.subFolders, newId, separator);
        }
        break;
      }
    }
  }
}

function changeChildrenIds(treeObj, newParentId, separator) {
  for (var i = 0; i < treeObj.length; i++) {
    var oldId = treeObj[i].id;
    var folderStruct = oldId.split(separator);
    var folderName = folderStruct.pop();
    var folderContainerObj = document.getElementById(oldId + "_Container");
    var folderContentsObj = document.getElementById(oldId + "_Contents");
    var folderNameObj = document.getElementById(oldId + "_Name");
    var newId = newParentId + separator + folderName;
    treeObj[i].id = newId;
    treeData[newId] = treeData[oldId];
    treeData[oldId] = undefined;
    if (folderContainerObj){
      folderContainerObj.id = newId + "_Container";
      folderContainerObj.rowId = newId;
    }
    if (folderContentsObj) {
      folderContentsObj.id = newId + "_Contents";
    }
    if (folderNameObj) {
      folderNameObj.id = newId + "_Name";
    }
    if(treeObj[i].subFolders){
      changeChildrenIds(treeObj[i].subFolders, treeObj[i].id, separator);
    }
  }
}

function clearTree(containerID) {
  var container = document.getElementById(containerID);
  lastOpenedTreeRow = undefined;

  var freeSpaceObj = "";
  while (container.firstChild) {
    if(container.firstChild.id == "FreeSpace") {
      freeSpaceObj = container.firstChild;
    }
    container.removeChild(container.firstChild);
  }

  if ( freeSpaceObj ) {
    container.appendChild(freeSpaceObj);
  }
}

function treeRowExist(newFolderName, parentId, useSlash) {
  if(useSlash) {
    if (parentId == "/") {
      var newContainerId = "/" + newFolderName + "_Container";
    } else {
      var newContainerId = parentId + "/" + newFolderName + "_Container";
    }  
  } else {
    var newContainerId = parentId + "." + newFolderName + "_Container";
  } 

  if (document.getElementById(newContainerId)) {
    return true;
  } else {
    return false;
  }    
}


function updateUnseen() {
  folderObj = document.getElementById(lastOpenedTreeRow + "_Name");
  if ( !folderObj ) return;
  folderName = lastOpenedTreeRow.substr(  lastOpenedTreeRow.lastIndexOf(".") + 1  );
  if ( unreadNumbers > 0 ) {
    addClassModifier(folderObj, "Unread");        
    folderObj.firstChild.innerHTML = folderName + " (" + unreadNumbers + ")";
  } else {
    removeClassModifier(folderObj, "Unread");
    folderObj.firstChild.innerHTML = folderName ;
  }
}

function getNextFolder ( subFolders, newFolderName, parentId ) {
  try {
    var folderNames = new Array(newFolderName);
    for ( i=0; i<subFolders.length; i++ ) {
      subFolderName = subFolders[i].name;
      if ( parentId == "INBOX" ) {
        if (!( subFolderName == "Drafts" || 
               subFolderName == "Sent" || 
               subFolderName == "Junk" || 
               subFolderName == "Trash" ) ) {
          folderNames.push( subFolderName );
        }
      } else {
        folderNames.push( subFolderName );
      }  
    }
    folderNames.sort(charOrdA);
    
    var folderPos = indexOf( folderNames, newFolderName);
    if ( folderPos < subFolders.length ) {
      nextFolderName = folderNames[folderPos + 1];
      for ( i=0; i<subFolders.length; i++ ) {
        if (subFolders[i].name == nextFolderName ) {
          nextFolderObj = document.getElementById( subFolders[i].id + "_Container");
          nextFolderObj.pos = i;
          return nextFolderObj;
        }
      }
    }
  } catch(e) {}  
  return false;
}

function charOrdA(a, b){
  a = a.toLowerCase(); 
  b = b.toLowerCase();
  if (a>b) return 1;
  if (a <b) return -1;
  return 0; 
}

// ####### menu.js #######
// Functions for the drawing of dropdown menus

/*
 * Constants
 */
var ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split('');
ALPHABET.unshift("ALL");

var NEVER         = -1;
var ALWAYS        =  0;
var ONLY_ONE      =  1;
var NONE_OR_ONE   =  2;
var ONE_OR_MORE   =  3;
var MORE_THAN_ONE =  4;

var DENY   = -1;
var PUBLIC =  0;
var READ   =  1;
var RW     =  2;
var ADMIN  =  3;

var acLookup = new Object();
acLookup["DENY"] = -1;
acLookup["PUBLIC"] = 0;
acLookup["READ"] = 1;
acLookup["RW"] = 2;
acLookup["ADMIN"] = 3;

var menuAccess = "";

/*
 * Objects
 */
var searchOptions = {
  enabled: false,
  searchURL: "",
  searchURLSize: "small",
  searchURLName: "",
  filterFunction: nothing,
  selectFilterFunction: nothing,
  selectFilter: false,
  selectPosition: "",
  searchText: "",
  selectedFilter: null,
  selectedFilterOption: "",
  selectedFilters: new Array(),
  filterDefaults: new Array(),
  searchFieldSelector: new Array(),
  searchFieldSelectorFunction: nothing,
  searchFieldDefault: "",
  getQueryString: function() {
    // the queryStr is escaped because otherwise search below will
    // produce JS errors when searching for items with characters
    // like single quotes
    queryStr = "query=" + escape(this.searchText);
    for (filter in this.selectedFilters) {
      queryStr += "&" + filter + "=" + this.selectedFilters[filter];
    }
    if (this.searchFieldSelector.length) {
      var searchField = document.getElementById("SearchFieldSelector");
      var sfSelected = this.searchFieldSelector[searchField.selectedIndex];

      queryStr += "&searchField=" + sfSelected.value;
    }

    return queryStr;
  },
  clearSearchText: function() {
    searchBox.value = "";
    this.searchText = "";
    searchBoxBlur(searchBox);
  },
  addSearchFieldSelector: function(name, value) {
    var sfSel = new Object();
    sfSel.name = name;
    sfSel.value = value;

    this.searchFieldSelector.push(sfSel);
  }
};

var menuRegistry = {
  // Store the default menus.
  menus: new Object(),
  menuOrder: new Array("FILE", "EDIT", "VIEW", "TOOLS", " CUSTOMS "),
  // Default menus have default text that can't be changed.
  menuTitles: new Object(),
  actionMenus: new Object(), // Stores the menu that an action is in.

  // The order of custom menus.
  customsOrder: new Array(),
  
  groups: new Array(),
  groupsIndex: new Array(),
  actionGroups: new Array(), // Stores the group that an action is in.
  actionCount: 0,

  drawMe: true,

  addMenu: function ( menuCode, menuText ) {
    if (!menuText) {
      menuText = menuCode.toLowerCase();
      menuText = menuText.charAt(0).toUpperCase() + menuText.substr(1);
    }
    menu = new menuDef(menuCode, menuText);
    if (this.menus[menuCode]) {
      alert("Menu " + menuCode + " already exists!");
    } else {
      this.menus[menuCode] = menu;
      this.customsOrder.push(menuCode);
    }

    return menu
  },

  addMenuObj: function (menuObj) {
    /* This function should only be used by the menu initialization
       code!  You have been warned! */
    this.menus[menuObj.code] = menuObj;
    this.menuTitles[menuObj.code] = menuObj.name;
  },

  getMenu: function (menuCode) {
    /* This will either return the menu, or undefined. */
    return this.menus[menuCode];
  },

  getAction: function (actionCode) {
    /* first get the menu of the action, then get the
       action from the menu */
    menuCode = this.actionMenus[actionCode];
    if (menuCode) {
      menu = this.getMenu(menuCode);
      return menu.getAction(actionCode);
    }
    
    return undefined;
  },

  draw: function () {
    removed = false;
    if (!this.drawMe || (!this.actionCount && !searchOptions.enabled)) {
      removed = true;
      menubar.parentNode.removeChild(menubar);      
    } else if (!this.actionCount && searchOptions.enabled) {
      /* No actions, but search enabled */
      menuButton = menuButtonTemplate.cloneNode(true);
      menuButton.style.visibility = "hidden";
      /* adding a blank button so that the search bar floats:right without any problems */
      menubar.appendChild(menuButton);
    }

    drawnMenus = 0;
    for (var i = 0; i < this.menuOrder.length; i++) {
      
      if (this.menuOrder[i] == " CUSTOMS ") {
        for (var j = 0; j < this.customsOrder.length; j++) {
          menu = this.menus[this.customsOrder[j]]
          drawn = menu.draw();
          if (drawn) { drawnMenus++ };
        }
      } else {
        menu = this.menus[this.menuOrder[i]]
        drawn = menu.draw();
        if (drawn) { drawnMenus++ };
      }
    }
    
    if (!drawnMenus && !searchOptions.enabled && !removed) {
      menubar.parentNode.removeChild(menubar);
    }
  }
};

var highlightedFilter;
var visibleOptions;
var useNewFilters = false;
var newFilterOptions = new Object; // Store new options before applying them.

var toolbarRegistry = {
  buttons: new Object(),
  buttonsOrder: new Array(),
  buttonCount: 0,
  filters: new Object(),
  filterCodes: new Array(),
  filterLabels: new Object(),
  filterObjects: new Object(),
  filterLookups: new Object(),
  buttonLabels: new Object(),
  filterCount: 0,
  tipTexts: new Object(),
  filterTypes: new Object(),
  
  drawMe: true,

  addButton: function( action ) {
    this.buttons[action.code] = action;
    this.buttonsOrder.push(action.code);
    this.buttonCount++;
  },

  addFilter: function( filterCode, value, text, type ) {
    filterGroup = this.filters[filterCode];
    if (!filterGroup) {
      filterGroup = new Array();
      this.filterCount++;
      this.filterCodes.push(filterCode);
      this.filterTypes[filterCode] = type;
    }

    filterLookup = this.filterLookups[filterCode];
    if (!filterLookup) {
      filterLookup = new Object();
    }
    filterLookup[value] = text;


    filter = new filterDef(value, text);
    filterGroup.push(filter);
    this.filters[filterCode] = filterGroup;
    this.filterLookups[filterCode] = filterLookup;
  },
  
  getFilterGroup: function( filterCode ) {
    return this.filters[filterCode];
  },

  getFilter: function( filterCode ) {
  },

  addFilterLabel: function( filterCode, label) {
    this.filterLabels[filterCode] = label;
  },

  addButtonLabel: function( buttonCode, label) {
    this.buttonLabels[buttonCode] = label;
  },

  addButtonToolTip: function( buttonCode, tipText ) {
    this.tipTexts[buttonCode] = tipText;
  },

  draw: function() {
    if (this.filterCount && !this.buttonCount) {
      /* There are filters, but no buttons */
      dummy = toolButtonTemplate.cloneNode(true);
      dummy.style.visibility = "hidden";
      toolButtonContainer.appendChild(dummy);
    } else if (!this.filterCount && !this.buttonCount) {
      /* There are neither filters, nor buttons */
      toolbar.parentNode.removeChild(toolbar);
    }

    drawnButtons = 0;
    var addToFilterBar;
    for (var i = 0; i < this.buttonsOrder.length; i++) {
      action = this.buttons[this.buttonsOrder[i]];
      addToFilterBar = false;
      
      if (!action) {
        alert(this.buttonsOrder[i]);
      }
      if (hasAccess(action.displayLimit)) {
        var button = toolButtonTemplate.cloneNode(true);
        button.firstChild.nodeValue = action.name;
        button.menuAction = action.code;
        button.id = action.code + "_BUTTON";

        // float the toolbutton if the action has been 
        // initiliazed with floated. IE/Moz access the float style
        // differently because float is a reserved word in JS.
        if ( action.floated ) {
          //button.style.styleFloat = action.floated;
          //button.style.cssFloat = action.floated;
          addToFilterBar = true;
        }

        // add icon if defined
        if (action.icon) {
          newIcon = iconTemplate.cloneNode(true);
          newIcon.src = action.icon;
          if (ie) {
            newSpan = document.createElement("span");
            newSpan.innerHTML = "&nbsp;";
            button.insertBefore(newSpan, button.firstChild);
          } else {
            //newIcon.style.paddingRight = "0.5em";
          }
          newIcon.style.height = "27";
          newIcon.style.width = "27";
          newIcon.style.verticalAlign = "middle";
          var newBr = document.createElement("br");
          button.insertBefore(newBr, button.firstChild);
          button.insertBefore(newIcon, button.firstChild);

          if (ie) {
            addClassModifier(button, "IEIconButton");
          } else {
            addClassModifier(button, "IconButton");
          }

          ss_attachEvent(button, "mouseover", addBorder);
          ss_attachEvent(button, "mouseout", removeBorder);
        }                                                                

        if (this.buttonLabels[action.code]) {
          label = labelTemplate.cloneNode(true);
          label.firstChild.nodeValue = this.buttonLabels[action.code];
          if (addToFilterBar) {
            filterBar.appendChild( label );
          } else {
            toolButtonContainer.appendChild( label );
          }
        }

        if (addToFilterBar) {
          filterBar.appendChild( button );
        } else {
          toolButtonContainer.appendChild( button );
        }

        if (action.icon && button.offsetWidth < 72) {
          // Minimum 72 pixel width for toolbar buttons.
          button.style.width = "72px";
        }
 
        action.toolButton = button;
        
        if (this.tipTexts[action.code]) {
          tooltip = tooltipTemplate.cloneNode(true);
          tooltip.firstChild.nodeValue = this.tipTexts[action.code];
          tooltip.id = action.code + "Tip";
          pageBody.insertBefore( tooltip, fixedTop );
          button.tipId = tooltip.id;
        }
        
        if (action.disabled || action.enableLimit != ALWAYS) {
          /* If the action was disabled before it was drawn, the disable
             function needs to be called again to actually disable the
             buttons */
          disableMenuAction(action);
        }
        drawnButtons++;
        // Hide the button 
        if (action.hidden) {
          hideMenuAction(action.code);
        }
      }
    }

    if (!drawnButtons && !this.filterCount && toolbar.parentNode) {
      toolbar.parentNode.removeChild(toolbar);
    }

    var filterLabels = document.getElementById("FilterLabels");
    var filterOptions = document.getElementById("FilterOptions");

    if (useNewFilters) {
      var searchLink = document.createElement("SPAN");
      var tableIcon = document.createElement("IMG");
      var br = document.createElement("BR");
      var optionText = document.createTextNode("Display Options");
      tableIcon.src = imagesURL + "/iconset/ss_table_gear.png";
      tableIcon.style.height = "27";
      tableIcon.style.width = "27";
      searchLink.appendChild(tableIcon);
      searchLink.appendChild(br);
      searchLink.appendChild(optionText);
      searchLink.style.textAlign = "center";
      searchLink.style.paddingRight = "5px";
      searchLink.style.cursor = "pointer";
      searchLink.style.position = "absolute";
      searchLink.style.right = "5px";
      searchLink.id = "DisplayOptionsSpan";
      searchLink.style.top = menubar.offsetHeight + 8;
      ss_attachEvent(searchLink, "click", showFilterOptions);
      filterBar.appendChild(searchLink);
    }

    for (var i = 0; i < this.filterCount; i++) {
      filterCode = this.filterCodes[i];
      filterGroup = this.filters[filterCode];
      filterLookup = this.filterLookups[filterCode];
      filterType = this.filterTypes[filterCode];
      if ( filterType == "filterBreak") {
        if (!useNewFilters) {
          var br = document.createElement("br");
          filterBar.appendChild(br);
        }
      } else {


      var optionsDiv = document.createElement("div");
      optionsDiv.id = filterCode + "Options";
      optionsDiv.className = "FilterOptionsList";

      filterOptions.appendChild(optionsDiv);

      if (filterGroup.length) {
        if (args[filterCode]) {
          filterDefault = args[filterCode];
        } else {
          filterDefault = searchOptions.filterDefaults[filterCode];
        }

        if (this.filterLabels[filterCode]) {
          labelText = this.filterLabels[filterCode];

          if (!useNewFilters) {
            holder = filterHolder.cloneNode(true);
            label = labelTemplate.cloneNode(true);
            label.innerHTML = labelText.replace(/ /g, "&nbsp;");
            holder.appendChild(label);
            if (filterType == "txt") {
              dropdown = textFilterTemplate.cloneNode(true);
              dropdown.value = filterGroup[0].value;
              searchOptions.selectedFilters[filterCode] = dropdown.value;
            } else {
              dropdown = dropdownTemplate.cloneNode(true);
            }
            dropdown.code = filterCode;
            dropdown.id = filterCode;
            holder.appendChild(dropdown);


          } else {
            var newLabel = document.createElement("div");
            if (!filterDefault) {
              filterDefault = filterGroup[0].value;
            }
            if (filterType == "txt") {
              filterText = filterGroup[0].value;
            } else {
              filterText = filterLookup[filterDefault];
            }

            newLabel.innerHTML = "<b>" + labelText + " </b><span>" + filterText + "</span>";
            newLabel.id = filterCode + "Label";
            newLabel.filterCode = filterCode;
            newLabel.filterType = filterType;
            newLabel.style.padding = "2px";
            newLabel.style.paddingRight = "5px";
            newLabel.style.cursor = "pointer";
            ss_attachEvent(newLabel, "click", selectFilter);
            ss_attachEvent(newLabel, "mousemove", delayedSelectFilter);
            ss_attachEvent(newLabel, "mouseout", clearDelayedFilter);
            ss_attachEvent(newLabel, "mouseover", underlineFilter);
            filterLabels.appendChild(newLabel);
          }
        } else {
          if (!useNewFilters) {
            dropdown = dropdownTemplate.cloneNode(true);
            dropdown.code = filterCode;
            dropdown.id = filterCode;
            holder.appendChild(dropdown);
          }
        }

        if (!useNewFilters) {
          filterBar.appendChild(holder);
        }

        if (filterType == "txt") {
          if (useNewFilters) {
            dropdown = textFilterTemplate.cloneNode(true);
            dropdown.onchange = null;
            ss_attachEvent(dropdown, "keyup", selectFilterOption);
            ss_attachEvent(dropdown, "change", selectFilterOption);
            dropdown.value = filterGroup[0].value;
            dropdown.code = filterCode;
            dropdown.id = filterCode;
            dropdown.style.width = "100%";
            dropdown.filterType = filterType;
            optionsDiv.appendChild(dropdown);
            searchOptions.selectedFilters[filterCode] = dropdown.value;
          }
        } else {
          for (var j = 0; j < filterGroup.length; j++) {
            filter = filterGroup[j];

            if (j == 0) {
              /*
               * If registering filters then the first filter in the list is
               * initially the default search.
               */
              searchOptions.selectedFilters[filterCode] = filter.value;
            }
            
            if (!useNewFilters) {
              filter.draw(dropdown, filterOptions, filterDefault);
            } else {
              filter.draw(optionsDiv, filterOptions, filterDefault);
            }
          }
        }

        if (!useNewFilters) {
          this.filterObjects[filterCode] = dropdown;
        }
      }
    }
    }
  }
};

var buttonbarRegistry = {
  groups: new Object(),
  groupsOrder: new Array(),
  actionGroups: new Object(),

  buttons: new Object(),
  buttonsOrder: new Array(),
  buttonsCount: 0,

  addGroup: function (groupCode) {
    group = new groupDef(groupCode);
    this.groups[groupCode] = group;
    this.groupsOrder.push(groupCode);

    return group;
  },

  getGroup: function (groupCode) {
    return this.groups[groupCode];
  },

  getAction: function (actionCode) {
    groupCode = this.actionGroups[actionCode];
    if (groupCode) {
      group = this.getGroup(groupCode);
      action = group.getAction(actionCode);
      return action;
    }

    return undefined;
  },

  drawMe: true,

  draw: function () {
    if (this.buttonsCount) {
      for (i = 0; i < this.groupsOrder.length; i++) {
        groupCode = this.groupsOrder[i];
        group = this.groups[groupCode];
      }
    } else {
      bottomBar.parentNode.removeChild(bottomBar);
    }
  }
}

function actionDef( actionCode, func, name, important, enableLimit, displayLimit, disableOnClick, shortcut, selected, floated, icon ) {
  this.code = actionCode;
  this.name = name;
  this.func = func;

  this.important = important;
  this.enableLimit = enableLimit;
  this.displayLimit = displayLimit;
  this.disableOnClick = disableOnClick;
  this.shortcut = shortcut;
  this.selected = selected;
  this.floated = floated;

  this.menuOption = undefined;
  this.toolButton = undefined;
  this.disabled = false;

  this.tooltip = undefined;

  this.icon = icon;
  this.id = actionCode;
};

actionDef.prototype.draw = function(pulldown) {
  if (hasAccess(this.displayLimit)) {

    var option = pulldownOptionTemplate.cloneNode(true);
    
    /* Load up the child nodes from the template clone of the 
       pulldown item */
    children = option.firstChild.firstChild.firstChild.childNodes;
    option.id = this.code + "_DIV";
    option.className = "PulldownOption";

    /* Show the icon if defined. */
    image = children[0].firstChild;
    if (this.icon) {
      image.src = this.icon;
    }

    /* assign the code to the action, tell it where it lives */
    option.menuAction = this.code;
    pulldown.appendChild( option );
    this.menuOption = option;
    
    /* if this item is supposed to be a selected element (such as 
       Day, Week, (x) Month), show it as such in the menu my making
       the Selected div visible */
    if (this.selected) {
      /* add a checkmark to the menu item */
      enableMenuActionSelected( this )
    }

    /* give the button the appropiate name */
    children[1].lastChild.lastChild.nodeValue = this.name;

    /* if there's a shortcut give it the appropriate key name */
    if (this.shortcut) {
      addMenuActionShortcut( this, this.shortcut )
    }

    if (this.disabled || action.enableLimit != ALWAYS) {
      /* If the action was disabled before it was drawn, the disable
         function needs to be called again to actually disable the
         buttons */
      disableMenuAction(this);
    }
    return true;
  }
  return false;
};

function spacerDef() { this.code = "SPACER" }
spacerDef.prototype.draw = function(pulldown) {
  var spacer = document.createElement("HR");
  pulldown.appendChild(spacer);
  return true;
};

function filterDef( value, text ) {
  this.value = value;
  this.text = text;
}
filterDef.prototype.draw = function(optionsDiv, filterOptions, filterDefault) {
  if (!useNewFilters) {
    option = optionTemplate.cloneNode(true);
    option.firstChild.nodeValue = this.text;
    option.value = this.value;
    option.filter = filterCode;
    
    dropdown.appendChild(option);
    if (this.value == filterDefault) {
      dropdown.selectedIndex = (dropdown.options.length - 1);
      searchOptions.selectedFilters[filterCode] = this.value;
    }
  } else {
    optionDiv = document.createElement("div");
    optionDiv.innerHTML = this.text;
    optionDiv.value = this.value;
    optionDiv.code = filterCode;
    optionDiv.style.cursor = "pointer";
    optionsDiv.appendChild(optionDiv);
    ss_attachEvent(optionDiv, "click", selectFilterOption);
    ss_attachEvent(optionDiv, "mouseover", underlineFilter);
    ss_attachEvent(optionDiv, "mouseout", resetFilterOption);
    if (this.value == filterDefault) {
      searchOptions.selectedFilters[filterCode] = this.value;
    }
  }
}

function menuDef( menuCode, name ) {
  this.code = menuCode;
  this.name = name;
  
  /*
    These arrays hold the order of the menus.  The special entry "
    CUSTOMS " denotes where in the menu custom actions are placed.
    There can only be one " CUSTOMS " per menu.  Note that the space
    before and after CUSTOMS is mandatory and used to prevent it
    clashing with any other custom action code.
  */
  this.order = new Array(" CUSTOMS ");
  this.titles = new Object();
  this.customs = new Array();

  this.actions = new Object();
  this.actionCount = 0;
  this.actionLimits = new Object();

  /* Every menu should have a spacer by default. */
  var spacer = new spacerDef();
  this.actions["SPACER"] = spacer;
  this.actionCount++;
};

menuDef.prototype.addAction = function( actionCode, func, name, important,
                                        enableLimit, displayLimit,
                                        disableOnClick, shortcut, 
                                        selected, floated, icon ) {

  title = this.titles[actionCode];
  if (title) {
    name = title;
  } else {
    this.customs.push(actionCode);
    this.titles[actionCode] = name;
  }

  action = new actionDef(actionCode, func, name, important, enableLimit, 
                         displayLimit, disableOnClick, shortcut, 
                         selected, floated, icon );
  this.actions[actionCode] = action;
  this.actionCount++;
  if (this.actionLimits[enableLimit]) {
    this.actionLimits[enableLimit].push(actionCode);
  } else {
    this.actionLimits[enableLimit] = new Array(actionCode);
  }

  menuRegistry.actionMenus[actionCode] = this.code;
  menuRegistry.actionCount++;

  /* Make sure to add it to the toolbar if it's important */
  if (action.important) {
    toolbarRegistry.addButton(action);
  }

  return action;
};

menuDef.prototype.getAction = function( actionCode ) {
  return this.actions[actionCode];
};

menuDef.prototype.listActions = function() {
  return this.actions;
};

menuDef.prototype.addSpacer = function( menuCode ) {
  var spacer = new spacerDef();
  this.actions["SPACER"] = spacer;
  this.actionCount++;
  this.customs.push("SPACER");
}
  
menuDef.prototype.draw = function() {
  if (this.actionCount) {
    menuButton = menuButtonTemplate.cloneNode(true);
    addText(this.name, menuButton);
    //menuButton.firstChild.nodeValue = this.name; // first child: #text node
    // menuButton.id = some unique id if we care.
    menubar.appendChild( menuButton );
    /*
     * Create actual pulldown container
     */
    pulldown = pulldownTemplate.cloneNode(true);
    pulldown.style.visibility = "hidden";
    pulldown.style.overflow = "auto";
    pulldown.id = this.code + "_pulldown";

    /*
     * Create pulldown frame to obscure select lists in IE6.
     */
    pulldownFrame = pulldownFrameTemplate.cloneNode(true);
    pulldownFrame.style.visibility = "hidden";
    pulldownFrame.style.overflow = "auto";
    pulldownFrame.id = this.code + "_pulldownFrame";

    /*
     * Create boundary to close the pulldown with
     */
    pulldownBoundary = document.createElement("div");

    /* Uncomment these lines to see the boundary area */
    //pulldownBoundary.style.backgroundColor = "red";
    //pulldownBoundary.style.opacity = .2;

    pulldownBoundary.style.zIndex = "8";
    pulldownBoundary.style.visibility = "hidden";
    pulldownBoundary.style.position = "absolute";
    pulldownBoundary.onmouseover = closeMenus;
    pulldownBoundary.id = this.code + "_pulldownBoundary";

    /*
     * Create boundary buffer, an area where you're off the 
     * pulldown, but the menu doesn't close.
     */
    pulldownBoundaryBuffer = document.createElement("div");

    /* Uncomment these lines to see the buffer area */
    //pulldownBoundaryBuffer.style.backgroundColor = "blue";
    //pulldownBoundaryBuffer.style.opacity = .2;

    pulldownBoundaryBuffer.style.zIndex = "9";
    pulldownBoundaryBuffer.style.visibility = "hidden";
    pulldownBoundaryBuffer.style.position = "absolute";
    pulldownBoundaryBuffer.id = this.code + "_pulldownBoundaryBuffer";

    /*
     * Create drop down shadow for pulldown. Oooh purdy.
     * Uses the TransLight class in style.css.
     */
    pulldownShadow = document.createElement("div");
    pulldownShadow.className = "TransLight";
    pulldownShadow.style.backgroundColor = "black";
    pulldownShadow.style.visibility = "hidden";
    pulldownShadow.style.zIndex = "8";
    pulldownShadow.style.position = "absolute";
    pulldownShadow.style.overflow = "auto";
    pulldownShadow.id = this.code + "_pulldownShadow";

    /*
     * IE weirdness: if we use document.body.appendChild() we get 
     * "Operation Aborted" followed by "Page Cannot Be Displayed / DNS Error"
     * as soon as it hits the closing </script> for the current code block.
     */
    document.body.insertBefore( pulldown, 
                                document.body.firstChild );
    document.body.insertBefore( pulldownBoundary, 
                                document.body.firstChild );
    document.body.insertBefore( pulldownBoundaryBuffer, 
                                document.body.firstChild );
    document.body.insertBefore( pulldownShadow, 
                                document.body.firstChild );
    document.body.insertBefore( pulldownFrame,
                                document.body.firstChild );
    /* Place pulldown right under its associated menu button */
    pulldown.style.left = getPosX(menuButton) + "px";
    pulldown.style.top  = ( getPosY(menuButton) + 
                            menuButton.offsetHeight + 1 ) + "px";

    /* Place pulldown frame right under its pulldown. */
    pulldownFrame.style.left   = pulldown.style.left;
    pulldownFrame.style.top    = pulldown.style.top;
   
    /*
     * Place pulldownBoundary and pulldownBoundaryBuffer
     * right under its associated menu button & pulldown.
     */
    pulldownBoundary.style.left = (getPosX(menuButton) - 80) + "px";
    pulldownBoundary.style.top  = ( getPosY(menuButton) + 
                            menuButton.offsetHeight + 1 ) + "px";

    pulldownBoundaryBuffer.style.left = (getPosX(menuButton) - 10) + "px";
    pulldownBoundaryBuffer.style.top  = ( getPosY(menuButton) + 
                            menuButton.offsetHeight + 1 ) + "px";


    /*
     * Place pulldownShadow under and slightly to the left and below 
     * it's associated pulldown.
     */    
    pulldownShadow.style.left = (getPosX(menuButton) + 2) + "px";
    pulldownShadow.style.top  = ( getPosY(menuButton) + 
                            menuButton.offsetHeight + 3  ) + "px";
    
    /* 
     * Connect the pulldown object to its menu button.
     * This will be used by its onclick event handler.
     */
    menuButton.menuPulldown = pulldown;
    pulldown.menuButton = menuButton;
    menuButton.menuPulldownBoundary = pulldownBoundary;
    menuButton.menuPulldownBoundaryBuffer = pulldownBoundaryBuffer;
    menuButton.menuPulldownShadow = pulldownShadow;
    menuButton.menuPulldownFrame = pulldownFrame;

    /*
     * Set a handler for clicking outside an active area 
     * (this will close the open menus)
     */
    document.body.onclick = defaultClickHandler;

    var drawnActions = new Array();
    var lastDrawn = "";
    var drawn = false;

    for (var i = 0; i < this.order.length; i++) {
      if (this.order[i] == " CUSTOMS ") {
        for (var j = 0; j < this.customs.length; j++) {
          action = this.actions[this.customs[j]];
          if (action) {
            if (!(action.code == "SPACER" && lastDrawn == "SPACER") &&
                !(action.code == "SPACER" && lastDrawn == "")) {
              drawn = action.draw(pulldown);
              
              if (drawn) {
                drawnActions.push(action.code);
                lastDrawn = action.code;
              }
            }
          }
        }
      } else {
        action = this.actions[this.order[i]];
        if (action) {
          if (!(action.code == "SPACER" && lastDrawn == "SPACER") &&
              !(action.code == "SPACER" && lastDrawn == "")) {
            drawn = action.draw(pulldown);

            if (drawn) {
              drawnActions.push(action.code);
              lastDrawn = action.code;
            }
          }
        }
      }
    }

    if (lastDrawn == "SPACER") {
      pulldown.removeChild(pulldown.lastChild);
    }

    pulldownBoundary.style.width = pulldown.offsetWidth + 160;
    pulldownBoundary.style.height = pulldown.offsetHeight + 81;

    pulldownBoundaryBuffer.style.width = pulldown.offsetWidth + 20;
    pulldownBoundaryBuffer.style.height = pulldown.offsetHeight + 11;

    pulldownShadow.style.width = pulldown.offsetWidth;
    pulldownShadow.style.height = pulldown.offsetHeight;

    pulldownFrame.style.height = pulldown.offsetHeight;
    pulldownFrame.style.width  = pulldown.offsetWidth;
 
    if (!drawnActions.length) {
      menuButton.parentNode.removeChild(menuButton);
      return false;
    }
    
    return true;
  }
};

function testfunc(){
  alert("Test function successfully called.");
}

function groupDef( code ) {
  this.code = code;
  
  this.actions = new Object();
  this.actionsOrder = new Array();
  this.actionLimits = new Array();
}

groupDef.prototype.addAction = function( code, name, func, enableLimit, 
                                         disableOnClick, shortcut, 
                                         floated, selected ) {
  action = new actionDef( code, func, name, false, enableLimit, PUBLIC, 
                          disableOnClick, shortcut, selected, floated );
  this.actions[code] = action;
  this.actionsOrder.push(code);
  buttonbarRegistry.actionGroups[code] = this.code;
  buttonbarRegistry.buttonsCount++;

  if (this.actionLimits[enableLimit]) {
    this.actionLimits[enableLimit].push(code);
  } else {
    this.actionLimits[enableLimit] = new Array(code);
  }

  return action;
};

groupDef.prototype.getAction = function(code) {
  return this.actions[code];
};

groupDef.prototype.listActions = function() {
    return this.actions;
};

var FILE_MENU = new menuDef("FILE", "File");
FILE_MENU.order = new Array("NEW_MESSAGE", "NEW_FOLDER", "NEW_FILE",
                            "NEW_WEB_LIST", "NEW_LIST_ITEM", "NEW_ITEM",
                            "NEW_CONTACT", "NEW_ORGANIZATION", "NEW_REQUEST",
                            "NEW_OPPORTUNITY", "NEW_LIST", "NEW_SUBSCRIBER",
                            "NEW_USER", "NEW_GROUP","NEW_GUEST", "NEW_BLOG",
                            "NEW_POST", "NEW_COMMENT", "NEW_REPLY",
                            "NEW_EVENT", "NEW_RULE", "NEW_MEMBER",
                            "NEW_EMAIL_ADDRESS", "NEW_ACCOUNT", "NEW_STAFF",
                            "NEW_SITE", "NEW_PAGE", "NEW_TASK", 
                            "NEW_DASHBOARD", "SPACER",
                            "OPEN", " CUSTOMS ");
FILE_MENU.titles.NEW_MESSAGE = "New Message";
FILE_MENU.titles.NEW_FOLDER = "New Folder";
FILE_MENU.titles.NEW_FILE = "New File";
FILE_MENU.titles.NEW_WEB_LIST = "New Web List";
FILE_MENU.titles.NEW_LIST_ITEM = "New List Item";
FILE_MENU.titles.NEW_ITEM = "New Item";
FILE_MENU.titles.NEW_CONTACT = "New Contact";
FILE_MENU.titles.NEW_LIST = "New List";
FILE_MENU.titles.NEW_SUBSCRIBER = "New Subscribers";
FILE_MENU.titles.NEW_USER = "New User";
FILE_MENU.titles.NEW_GROUP = "New Group";
FILE_MENU.titles.NEW_GUEST = "New Guest";
FILE_MENU.titles.NEW_BLOG = "New Blog";
FILE_MENU.titles.NEW_POST = "New Post";
FILE_MENU.titles.NEW_COMMENT = "New Comment";
FILE_MENU.titles.NEW_REPLY = "New Reply";
FILE_MENU.titles.NEW_EVENT = "New Event";
FILE_MENU.titles.NEW_RULE = "New Rule";
FILE_MENU.titles.NEW_MEMBER = "New Member";
FILE_MENU.titles.NEW_EMAIL_ADDRESS = "New Email Address";
FILE_MENU.titles.NEW_ACCOUNT = "New Email Account";
FILE_MENU.titles.NEW_STAFF = "New Staff";
FILE_MENU.titles.NEW_SITE = "New Site";
FILE_MENU.titles.NEW_PAGE = "New Page";
FILE_MENU.titles.NEW_TASK = "New Task";
FILE_MENU.titles.NEW_REQUEST = "New Request";
FILE_MENU.titles.OPEN = "Open";
FILE_MENU.titles.NEW_ORGANIZATION = "New Organization";
FILE_MENU.titles.NEW_OPPORTUNITY = "New Opportunity"; 
FILE_MENU.titles.NEW_DASHBOARD = "New Dashboard";

var EDIT_MENU = new menuDef("EDIT", "Edit");
EDIT_MENU.order = new Array("CLIPBOARD", "COPY", "MOVE", "DUPLICATE", "DELETE",
                            "DELETE_LIST", "SPACER", " CUSTOMS ", "SPACER", 
                            "SELECT_ALL", "DESELECT", "SPACER", "FIND",
                            "FIND_SUBSCRIBERS", "FIND_TASKS", "FIND_FILES",
                            "FIND_ACCOUNTS", "FIND_CONTACTS", "FIND_ITEMS",
                            "FIND_EVENTS");
EDIT_MENU.titles.CLIPBOARD = "Copy to Clipboard";
EDIT_MENU.titles.COPY = "Copy";
EDIT_MENU.titles.MOVE = "Move";
EDIT_MENU.titles.DUPLICATE = "Duplicate";
EDIT_MENU.titles.DELETE = "Delete";
EDIT_MENU.titles.DELETE_LIST = "Delete List";
EDIT_MENU.titles.SELECT_ALL = "Select All";
EDIT_MENU.titles.DESELECT = "Deselect";
EDIT_MENU.titles.FIND = "Find...";
EDIT_MENU.titles.FIND_SUBSCRIBERS = "Find Subscribers...";
EDIT_MENU.titles.FIND_TASKS = "Find Tasks...";
EDIT_MENU.titles.FIND_FILES = "Find Files & Folders...";
EDIT_MENU.titles.FIND_ACCOUNTS = "Find Users & Groups...";
EDIT_MENU.titles.FIND_CONTACTS = "Find Contacts...";
EDIT_MENU.titles.FIND_ITEMS = "Find Items...";
EDIT_MENU.titles.FIND_EVENTS = "Find Events...";

var VIEW_MENU = new menuDef("VIEW", "View");

var TOOLS_MENU = new menuDef("TOOLS", "Tools");
TOOLS_MENU.order = new Array(" CUSTOMS ", "ACCESS_CONTROL", "OPTIONS");
TOOLS_MENU.titles.ACCESS_CONTROL = "Access Control...";
TOOLS_MENU.titles.OPTIONS = "Options...";

menuRegistry.addMenuObj(FILE_MENU);
menuRegistry.addMenuObj(EDIT_MENU);
menuRegistry.addMenuObj(VIEW_MENU);
menuRegistry.addMenuObj(TOOLS_MENU);

buttonbarRegistry.addGroup("BOTTOMLEFT");
buttonbarRegistry.addGroup("BOTTOMCENTER");
buttonbarRegistry.addGroup("BOTTOMRIGHT");

var toolButtonTemplate;
var toolbar;
var toolButtonContainer;
var pulldownOptionTemplate;
var pulldownTemplate;
var menuButtonTemplate;
var menubar;
var letterBar;
var letterRow;
var letterCell;
var showLetterBar;
var bottomBar;
var bottomButtonTemplate;
var bottomLeft;
var bottomCenter;
var bottomRight;
var tabsSeparator;
var filterBar;
var labelTemplate;
var optionTemplate;
var dropdownTemplate;
var textFilterTemplate;
var searchBox;
var SearchImg;
var iconTemplate;
var tooltipTemplate;

/* Since IE doesn't have any attributes or functions that will tell
   you what the size of a window is, when we open a popup I store them
   here so that the popup can refer to them to find out how big it
   is. */
var popupWidth;
var popupHeight;

/*
 * Query arguments
 */
function getArgs() {
  var args = new Object();
  var query = location.search.substring(1);
  var pairs = query.split("&");
  var re = /\+/g;

  for (i = 0; i < pairs.length; i++) {
    var pos = pairs[i].indexOf('=');
    if (pos == -1) continue;
    var argname = pairs[i].substring(0, pos);
    var value = pairs[i].substring(pos+1);
    args[argname] = decodeURIComponent(value).replace(re, ' ');
  }

  return args;
}

var args = getArgs();

/*
 * Functions
 */
function menuShow() {
  /*
   * Set up the templates...
   */
  toolButtonTemplate     = getTemplate( "ToolButton",          true );
  toolbar                = getTemplate( "ToolBar",             false );
  toolButtonContainer    = getTemplate( "ToolButtonContainer", false );
  iconTemplate           = getTemplate( "IconTemplate",        false);
  pulldownOptionTemplate = getTemplate( "PulldownOption",      true );
  pulldownTemplate       = getTemplate( "Pulldown",            true );
  pulldownFrameTemplate  = getTemplate( "PulldownFrame",       true );
  menuButtonTemplate     = getTemplate( "MenuButton",          true );
  menubar                = getTemplate( "MenuBar",             false );
  letterBar              = getTemplate( "LetterBar",           false );
  letterRow              = getTemplate( "LetterRow",           false );
  letterCell             = getTemplate( "LetterCell",          true );
  searchBox              = getTemplate( "SearchBox",           true );
  searchImg              = getTemplate( "SearchImg",           true );  
  searchBar              = getTemplate( "SearchBar",           true );
  tabsSeparator          = getTemplate( "TabsSeparator",       true);
  tabsSeparatorContainer = getTemplate( "TabsSeparatorContainer", true);
  userIconTemplate       = getTemplate( "UsernameIcon",        true);
  tooltipTemplate        = getTemplate( "ToolTipTemplate",     true);
  fixedTop               = document.getElementById("FixedTop");
  pageBody               = document.getElementById("PageBody");

  // The getTemplate function unhides elements by default, but we want tooltips
  // to remain hidden.
  tooltipTemplate.style.visibility = "hidden";

  menuRegistry.draw();

  // Gets rid of ugly white space at the top of IE windows when there
  // are no tabs.
  if (!document.getElementById("ActiveTab")) {
    try {
      tabs = getTemplate("Tabs", true);
    } catch (e) {
    }
  } else {
    if (!toolbarRegistry.filterCount && !toolbarRegistry.buttonCount) {
      var tabs = document.getElementById("Tabs");
      var newSeparator = tabsSeparator.cloneNode(true);
      tabs.appendChild(newSeparator);
    }
  }
}

function searchBoxShow() {
  if (searchOptions.enabled) {
    if (searchOptions.searchText) {
      searchBox.value = searchOptions.searchText;
    } else if (args['query']) {
      searchOptions.searchText = args['query'];
      searchBox.value = args['query'];
      searchBox.style.color = "#000";
    }

    if (searchOptions.searchFieldSelector.length) {
      var selector = document.createElement("select");
      selector.id = "SearchFieldSelector";
      selector.style.height = 18;
      selector.style.fontSize = "smaller";
      selector.style.position = "absolute";
      ss_attachEvent(selector, "change", searchOptions.searchFieldSelectorFunction);

      for (var i = 0; i < searchOptions.searchFieldSelector.length; i++) {
        var field = searchOptions.searchFieldSelector[i];
        var fieldOpt = document.createElement("option");
        
        fieldOpt.innerHTML = field.name;
        fieldOpt.value = field.value;

        if (searchOptions.searchFieldDefault == field.value) {
          fieldOpt.selected = true;
        }

        selector.appendChild(fieldOpt);
      }

      selector.style.right = 218;
      selector.style.top = 2;
      searchBar.appendChild(selector);
    }

    searchBar.appendChild(searchBox);
    searchBar.appendChild(searchImg);
    searchImg.src = imagesURL + "/templates/search_circle.png";

    /* If there's no menu, but we need to show a search box, we put it
       in with the filters. */
    if (menuRegistry.drawMe) {
      menubar.appendChild(searchBar);
    } else {
      if(ie) {
        filterBar.style.position = "relative";
        filterBar.style.right = 218;
        searchBar.style.right = (toolButtonContainer.offsetWidth - 218);
        searchBar.style.top = 4;
      } else {
        filterBar.style.paddingRight = 218;
        searchBar.style.top = 4;
      }
      filterBar.appendChild(searchBar);
    }
  }
}

function toolbarShow() {
  filterBar           = getTemplate("FilterBar",           false);
  labelTemplate       = getTemplate("FilterLabel",         true);
  optionTemplate      = getTemplate("SearchOption",        true);
  dropdownTemplate    = getTemplate("SearchFilter",        true);
  textFilterTemplate  = getTemplate("SearchTextFilter",    true);
  filterHolder        = getTemplate("FilterHolder",        true);
  toolButtonContainer = getTemplate("ToolButtonContainer", false);
  
  toolbarRegistry.draw();
}

function filterShow() {
  toolbarShow();
  letterBarShow();
  /* Sometimes the searchbox is with the menus, sometimes it's with
     the filters... so we draw it last. */
  searchBoxShow();

  /* Set the height of the toolbar.  Since our toolButtonContainer and
     our filterBar are now floating, the div they're in doesn't get
     the right height. */
  toolHeight = toolButtonContainer.offsetHeight || filterBar.offsetHeight;
  if (toolbar.offsetHeight - toolHeight < 10) {
    toolbar.style.height = toolHeight;
  }
}

function newFilters() {
  useNewFilters = true;
}

function bottomShow() {
  bottomBar              = getTemplate( "BottomBar",           false);
  bottomButtonTemplate   = getTemplate( "BottomButton",        true  );
  bottomLeft             = getTemplate( "BottomLeft",          false );
  bottomCenter           = getTemplate( "BottomCenter",        false );
  bottomRight            = getTemplate( "BottomRight",         false );

  if (buttonbarRegistry.buttonsCount) {
    drawBottomButtons("BOTTOMLEFT", bottomLeft);
    drawBottomButtons("BOTTOMCENTER", bottomCenter);
    drawBottomButtons("BOTTOMRIGHT", bottomRight);
  } else {
    bottomBar.parentNode.removeChild(bottomBar);
  }
  //buttonbarRegistry.draw();
};

function drawBottomButtons(groupName, element) {
  group = buttonbarRegistry.getGroup(groupName)
  actions = group.listActions();
  for (i = 0; i < group.actionsOrder.length; i++) {
    var action = actions[group.actionsOrder[i]];

    var button = bottomButtonTemplate.cloneNode(true);
    button.firstChild.nodeValue = action.name; // first child is the #text node
    button.menuAction = action.code;
    button.id = action.code + "_BOTTOM";
    element.appendChild( button );
    action.toolButton = button;

    if (action.disabled) {
      disableMenuAction(action);
    }
    if (action.hidden) {
      hideMenuAction(action.code);
    }
  }
}


function spacerShow() {
}

function letterBarShow() {
  /* Show the letter bar if necessary */
  if (showLetterBar) {
    selectedLetter = args.letter;
    if (!selectedLetter) {
      selectedLetter = 'ALL';
    }

    for (i = 0; i < ALPHABET.length; i++) {
      letter = ALPHABET[i];
      cell = letterCell.cloneNode(true);
      cell.firstChild.nodeValue = letter;
      cell.letter = letter;
      cell.id = "Letter_" + letter;
      if (selectedLetter == letter) {
        addClassModifier(cell, "AlphabetSelected");
        searchOptions.selectedFilters["letter"] = letter;
      } else {
        addClassModifier(cell, "Alphabet");
      }
      cell.align = "center";
      letterRow.appendChild(cell);
    }
    letterBar.style.visibility = "visible";
    hasMenu = true;
  } else {
    letterBar.parentNode.removeChild(letterBar);
  }
}

function changeSelectedLetter( newLetter ) {
   oldLetter = searchOptions.selectedFilters["letter"];
   if (!oldLetter) {
     oldLetter = "All";
   }
   if ( newLetter && oldLetter != newLetter) {
     var oldLetterObj = document.getElementById( "Letter_" + oldLetter );
     var newLetterObj = document.getElementById( "Letter_" + newLetter );     
     removeClassModifier(oldLetterObj, "AlphabetSelected");
     addClassModifier(oldLetterObj, "Alphabet");
     addClassModifier(newLetterObj, "AlphabetSelected");
     searchOptions.selectedFilters["letter"] = newLetter;
   }  

}


function addMenuAction( actionCode, func, name, menuCode, important, 
                        enableLimit, displayLimit, disableOnClick, 
                        shortcut, selected, floated, icon ) {
  /* Adds options to the dropdown menus and to the toolbar if they're
     marked as important */
  menu = menuRegistry.getMenu(menuCode);
  if (!menu) {
    menu = menuRegistry.addMenu(menuCode);
  }

  action = menu.addAction( actionCode, func, name, important,
                           enableLimit, displayLimit, disableOnClick, 
                           shortcut, selected, floated, icon );
  
}

function addButton( buttonCode, buttonText, buttonFunc, buttonLocation,
                    buttonEnableLimit, disableOnClick ) {
  /* Adds buttons to the bottom of the window.  Used for Ok, Cancel,
     etc...
  */

  if (!buttonLocation) {
    buttonLocation = "BOTTOMCENTER";
  } else {
    buttonLocation = "BOTTOM" + buttonLocation.toUpperCase();
  }

  if (!buttonEnableLimit) {
    buttonEnableLimit = ALWAYS;
  }

  group = buttonbarRegistry.getGroup(buttonLocation);
  if (!group) {
    group = buttonbarRegistry.addGroup(buttonLocation);
  }

  group.addAction(buttonCode, buttonText, buttonFunc, buttonEnableLimit,
                  disableOnClick);
};

function addSpacer(menuCode) {
  /* Adds a horizontal line to the dropdown menus.  Just a visual
     thing to make it look nice. */
  menu = menuRegistry.getMenu(menuCode);
  menu.addSpacer(menuCode);
}

function addFilter(filterCode, value, text, type) {
  /* Add a dropdown filter option */
  toolbarRegistry.addFilter(filterCode, value, text, type);
}

function addSelectFilter(filter, value, text, position, allText) {
  /* Add an atypical filter to the toolbar, one that is designed to trigger
     a popup or some other functionality when you choose "Select..." */
  addFilter(filter, position, allText);
  /* All should always be as first option and if text not the same as allText the second 
     should show and be selected */
  if ( text != allText ) {
    addFilter(filter, value, text);
    setFilterDefault( filter, value );
  } 
  addFilter(filter, position, "Select...");
}

function setSelectedFilter(value, text, position) {
  searchOptions.selectedFilter.options[0].value = value;
  searchOptions.selectedFilter.options[0].text = text;
  searchOptions.selectedFilter.options[searchOptions.selectedFilter.options.length - 1].value = position;
  // make sure searchOptions has the latest select data
  setSearchOptions( searchOptions.selectedFilter );
  // we need to call an extra function when the values are set to reload the page or submit a form
  setAdditionalSelectFilter( value, text, position );   
}

// this function can be overwitten by developers
function setAdditionalSelectFilter() {}


function addButtonLabel(buttonCode, label) {
  /* Add a label to the left of a button on the toolbar. */
  toolbarRegistry.addButtonLabel(buttonCode, label);
}

function addButtonToolTip(buttonCode, tipText) {
  /* Add a tooltip popup to a toolbar button */
  toolbarRegistry.addButtonToolTip(buttonCode, tipText);
}

function addFilterLabel(filterCode, label) {
  /* Add a label to a dropdown filter.  The text will appear to the
     left of the dropdown, in bold. */
  toolbarRegistry.addFilterLabel(filterCode, label);
}

function addFilterFunction( filterFunc ) {
  searchOptions.filterFunction = filterFunc;
}

function addSearchFieldSelectorFunction( sectorFunc ) {
  searchOptions.searchFieldSelectorFunction = sectorFunc;
}

function addSelectFilterFunction( filterFunc ) {
  /* Associate a function with the SelectFilters. This is triggered when
     someone chooses "Select..." on a filter item (if it is present). */
  searchOptions.selectFilterFunction = filterFunc;
}

function setFilterDefault( filter, defaultAction ) {
  searchOptions.filterDefaults[filter] = defaultAction;
}

function resetFilterDefault ( filter, value ) {
  //reset a filter to it's origin value after an item it selected.  
  obj = toolbarRegistry.filterObjects[filter];
  value = searchOptions.filterDefaults[filter];
  for( i=0; obj.length>i; i++ ) {
    if ( obj[i].value == value ) {
      obj[i].selected = true;
      searchOptions.selectedFilters[filter] = value;
      break;
    }
  }
}

function selectFilterDefault( filter, text, value ) {
  // obj = toolbarRegistry.getFilterGroup( filter );
  obj =  searchOptions.selectedFilter ;
  var matchFound = false;
  var len = obj.length;
  if (text.length > 42) {
    shortText = text.substr(0, 40) + "...";
  } else {
    shortText = text;
  }
  
  for (i=0; i<len; i++) {
    if (obj[i].value == value && (obj[i].text == text || obj[i].text == shortText)) {
      obj[i].selected = true;
      matchFound = true;
      break;
    }
  }
  if (!matchFound) {
    // we are doing it for CRM and last item is select which should be always at the end.
    var tempText = obj[len-1].text;
    var tempValue = obj[len-1].value;

    obj[len-1].text = shortText;
    obj[len-1].value = value;
    obj[len-1].selected = true;
    
    addFilter(filter, tempValue, tempText);
    obj[len] = new Option(tempText, tempValue, false, false);
    obj[len].filter = filter;

   }

  searchOptions.selectedFilters[filter] = value;
}

function setSearchOptions( filter ) {
  if(filter.options) {
    selected = filter.options[filter.selectedIndex];
    var isText = false;
    selectedVal = selected.value;
  } else {
    var isText = true;
    selectedVal = filter.value;
  }
  searchOptions.selectedFilter = filter; 

  // if the item is a SelectFilter, then flag it
  if (!isText && filter.options[filter.length - 1].text == "Select...") {
    searchOptions.selectFilter = true;
    // assign the position of the select filter
    searchOptions.selectPosition = filter.options[filter.length - 1].value;
    // set the select option to the first value in case they hit cancel
    filter.options[0].selected = 1;
  }
  else {
    searchOptions.selectFilter = false;
  }

  if (!isText) {
    searchOptions.selectedFilterOption = selected;
    searchOptions.selectedFilters[selected.filter] = selectedVal;
  } else {
    searchOptions.selectedFilters[filter.id] = selectedVal;
  }
  
};

function detectEnterKey(event, filter) {
  var key = event.which || event.keyCode;
  if (key == 13 && !useNewFilters) {
    setSearchOptions(filter);
    execFilterAction();
  }
}

function addSearchPopup( searchURL, size, name ) {
  /* Specify a URL to open in a popup window when a user does a
     search */
  searchOptions.searchURL = searchURL;
  searchOptions.searchURLSize = size;
  if (name) {
    searchOptions.searchURLName = name;
  }
}

function addSearchBox( defaultText ) {
  /* Show the search text input */
  if (defaultText) {
    searchOptions.searchText = defaultText;
  }

  searchOptions.enabled = true;
}

function addSearchFieldSelector( name, value ) {
  searchOptions.addSearchFieldSelector(name, value);
}

function setSearchFieldSelectorDefault( defaultField ) {
  /* The value passed to this function should be the value of one of the search
   * field selectors added with the function above. */
  searchOptions.searchFieldDefault = defaultField
}

function addLetterBar() {
  /* Tell the template to draw the alphabet bar. */
  showLetterBar = true;
}

function setAccess(access) {
  menuAccess = acLookup[access];
}

function noMenu() {
  menuRegistry.drawMe = false;
}

function setToolbarButtonOrder(buttonsOrder) {
  toolbarRegistry.buttonsOrder = buttonsOrder;
}

function setHiddenMenuActions( buttons ) {
  for ( i in buttons ) {
    var thisButton = buttons[i];
    
    for (var j = 0; j < toolbarRegistry.buttonsOrder.length; j++) {
      if (toolbarRegistry.buttonsOrder[j] == thisButton) {
        var action = toolbarRegistry.buttons[thisButton];
        action.hidden = 1;
      }
    }
    setHiddenBottomButtons("BOTTOMLEFT", thisButton);
    setHiddenBottomButtons("BOTTOMCENTER", thisButton);
    setHiddenBottomButtons("BOTTOMRIGHT", thisButton);
  }
}

function setHiddenBottomButtons(groupName, buttonName) {
  var group = buttonbarRegistry.getGroup(groupName);
  var actions = group.listActions(); 
   for (i = 0; i < group.actionsOrder.length; i++) {
     if (group.actionsOrder[i] == buttonName) {
       var action = actions[buttonName];
       action.hidden = 1;
     }
  }
}

function nothing() {};

function searchBoxBlur(searchBox) {
  window.textboxFocussed = false;
  if (!searchBox.value) {
    searchBox.style.color = "#888";
    searchBox.value = "Search Below";
    searchOptions.searchText = "";
  } else {
    searchOptions.searchText = searchBox.value;
  }
}

function searchBoxFocus(searchBox) {
  window.textboxFocussed = true;
  if (searchBox.value == "Search Below") {
    searchBox.value = '';
    searchBox.style.color = "#000";
  } else {
    searchBox.select();
  }
}

function execSearchEvent( obj, event ) {
  /* This function reads the keystrokes entered into the search box
     and calls execSearchAction when Enter is pressed */
  if (event.keyCode == 13) {
    searchOptions.searchText = obj.value;
    execSearchAction();
    return false;
  }
  return true;
}

function execSearchAction() {
  /* Execute the search action with the search text and an optional
     filter argument. */

  if (searchOptions.searchURL) {
    newSearchURL = searchOptions.searchURL;
    queryString = searchOptions.getQueryString();

    if (newSearchURL.indexOf("?") == -1) {
      newSearchURL += "?";
    } else {
      newSearchURL += "&";
    }
    newSearchURL += queryString;

    searchOptions.clearSearchText();
    openWindow(searchOptions.searchURLSize,
               newSearchURL,
               searchOptions.searchURLName);
  } else {
    execFilterAction();
  }
}


function execFilterAction() {
  /* Execute an associated funtion. If it's a regular filter, use the 
     filterFunction. If it's a SelectFilter, use the selectFilterFunction. (Tom) 
     As All is added as first item, we need to cal the function anyhow (alex).*/
  if (searchOptions.selectFilter) {
      searchOptions.selectFilterFunction(searchOptions);
  } else {
     searchOptions.filterFunction(searchOptions);
  }
}

function showFilterOptions() {
  var filterBox = document.getElementById("FilterBox");
  filterBox.style.display = "block";
}

function hideFilterOptions() {
  var filterBox = document.getElementById("FilterBox");
  filterBox.style.display = "none";

  if (highlightedFilter) {
    removeClassModifier(highlightedFilter, "FilterHighlighted");
    removeClassModifier(highlightedFilter, "DisplayOptionsSelectedBG");
  }

  if (visibleOptions) {
    visibleOptions.style.display = "none";
  }
}

var filterTimer;
function clearDelayedFilter() {
  clearTimeout(filterTimer);
  if (window.event && window.event.srcElement) {
    var filter = window.event.srcElement;
  } else {
    var filter = this;
  }

  filter.style.textDecoration = "none";
}

function underlineFilter() {
  if (window.event && window.event.srcElement) {
    var filter = window.event.srcElement;
  } else {
    var filter = this;
  }

  filter.style.textDecoration = "underline";
}

function resetFilterOption() {
  if (window.event && window.event.srcElement) {
    var filter = window.event.srcElement;
  } else {
    var filter = this;
  }

  filter.style.textDecoration = "none";
}

function delayedSelectFilter() {
  clearTimeout(filterTimer);
  if (window.event && window.event.srcElement) {
    var filter = window.event.srcElement;
  } else {
    var filter = this;
  }

  var filterId = filter.id;
  filterTimer = setTimeout("selectFilter('" + filterId + "')", 1000);
}

function selectFilter(filterId) {
  clearTimeout(filterTimer);
  var filter = document.getElementById(filterId);

  if (!filter) {
    if (window.event && window.event.srcElement) {
      var filter = window.event.srcElement;
    } else {
      var filter = this;
    }
  }
  
  var filterCode = filter.filterCode;
  if (!filterCode) {
    // IE gets a different element than FF does.  It gets the B instead of the
    // DIV.
    filter = filter.parentNode;
    filterCode = filter.filterCode;
  }

  var filterOptionsList = document.getElementById(filterCode + "Options");
  var filterOptionsBox = document.getElementById("FilterOptions");

  if (highlightedFilter) {
    removeClassModifier(highlightedFilter, "FilterHighlighted");
    removeClassModifier(highlightedFilter, "DisplayOptionsSelectedBG");
  }

  if (visibleOptions) {
    visibleOptions.style.display = "none";
  }
  
  addClassModifier(filter, "FilterHighlighted");
  addClassModifier(filter, "DisplayOptionsSelectedBG");

  filterOptionsList.style.display = "block";

  if (filterOptionsBox.offsetHeight > 200) {
    filterOptionsBox.style.height = "200px";
    filterOptionsList.style.height = "200px";
    filterOptionsBox.parentNode.style.height = "200px";
    filterOptionsBox.parentNode.style.overflow = "hidden";
  }
  
  highlightedFilter = filter;
  visibleOptions = filterOptionsList;
}

function selectFilterOption(e) {
  var filterBox = document.getElementById("FilterBox");

  if (window.event && window.event.srcElement) {
    var option = window.event.srcElement;
  } else {
    var option = this;
  }

  var filterLabel = document.getElementById(option.code + "Label");
  if ( option.filterType == "txt") { 
    selectedText = option.value;
    filterLabel.childNodes[1].innerHTML = selectedText;
    searchOptions.selectedFilters[option.code] = selectedText;
  } else {
    var optContainer = option.parentNode;
    for (var x = 0; x < optContainer.childNodes.length; x++) {
      var opt = optContainer.childNodes[x];
      opt.style.fontWeight = "normal";
    }

    option.style.fontWeight = "bold";

    var selected = option.value;
    var selectedText = option.innerHTML;
    var newSelected = new Object;

    newSelected.value = selected;
   
    newSelected.oldText = filterLabel.childNodes[1].innerHTML;
    filterLabel.childNodes[1].innerHTML = selectedText;
    newFilterOptions[option.code] = newSelected;
  }
  
  

  
}

function runNewFilter() {
  for (code in newFilterOptions) {
    var newOption = newFilterOptions[code];
    searchOptions.selectedFilterOption = newOption.value;
    searchOptions.selectedFilters[code] = newOption.value;
  }
  execFilterAction();
  hideFilterOptions();

  newFilterOptions = new Object;
}

function closeNewFilterWindow() {
  resetFilterOptions();
  hideFilterOptions();
}

function resetFilterOptions() {
  for (code in newFilterOptions) {
    var newOption = newFilterOptions[code];
    filterLabel = document.getElementById(code + "Label");
    filterLabel.childNodes[1].data = newOption.oldText;
  }
}

function defaultExit() {
  expires = new Date();
  expires.setFullYear( expires.getFullYear() + 1 );

  document.cookie = "lastVisitedPageBody=;expires=" 
    + expires.toGMTString() + ";path=/";
  document.location.href = "/";
}

function defaultExitLogout() {
  document.location = "/login/logout.pyt";
}

/*****************************************************************************
 * Interactive Menu
 *****************************************************************************/

openMenuButton = null;
openPulldown = null;
openPulldownBoundary = null;
openPulldownBoundaryBuffer = null;
openPulldownShadow = null;
openPulldownFrame = null;
  
/*
 * Called when user clicked on a menu button -> open pulldown
 */
function clickMenuButton( menuButton ){
  pulldown = menuButton.menuPulldown;
  pulldownBoundary = menuButton.menuPulldownBoundary;
  pulldownBoundaryBuffer = menuButton.menuPulldownBoundaryBuffer;
  pulldownShadow = menuButton.menuPulldownShadow;
  pulldownFrame = menuButton.menuPulldownFrame;
  if ( !openPulldown ){
    addClassModifier( menuButton, "Active" );
    pulldown.style.visibility = "visible";
    pulldownBoundary.style.visibility = "visible";
    pulldownBoundaryBuffer.style.visibility = "visible";
    pulldownShadow.style.visibility = "visible";
    pulldownFrame.style.visibility = "visible";
    openPulldown = pulldown;
    openPulldownBoundary = pulldownBoundary;
    openPulldownBoundaryBuffer = pulldownBoundaryBuffer;
    openPulldownShadow = pulldownShadow;
    openPulldownFrame = pulldownFrame;
    openMenuButton = menuButton;
  
  } else {
    addClassModifier( menuButton, "Hover" );
    pulldown.style.visibility = "hidden";
    pulldownBoundary.style.visibility = "hidden";
    pulldownBoundaryBuffer.style.visibility = "hidden";
    pulldownShadow.style.visibility = "hidden";
    pulldownFrame.style.visibility = "hidden";
    openPulldown = null;
    openPulldownBoundary = null;
    openPulldownBoundaryBuffer = null;
    openPulldownShadow = null;
    openPulldownFrame = null;
    openMenuButton = null;
  }
  if ( document.focusTrap ){
    document.focusTrap.focusTrap.focus();
  }
}

/*
 * Called when user hovers over a menu button
 */
function overMenuButton( menuButton ){
  pulldown = menuButton.menuPulldown;
  pulldownBoundary = menuButton.menuPulldownBoundary;
  pulldownBoundaryBuffer = menuButton.menuPulldownBoundaryBuffer;
  pulldownShadow = menuButton.menuPulldownShadow;
  pulldownFrame = menuButton.menuPulldownFrame;
  if (openPulldown) {
    /* close previously open pull-down, open the one under this button */
    removeClassModifier( openMenuButton );
    addClassModifier( menuButton, "Active" );
    openPulldown.style.visibility = "hidden";
    openPulldownBoundary.style.visibility = "hidden";
    openPulldownBoundaryBuffer.style.visibility = "hidden";
    openPulldownShadow.style.visibility = "hidden";
    openPulldownFrame.style.visibility = "hidden"
    pulldown.style.visibility = "visible";
    pulldownBoundary.style.visibility = "visible";
    pulldownBoundaryBuffer.style.visibility = "visible";
    pulldownShadow.style.visibility = "visible";
    pulldownFrame.style.visibility = "visible";
    openPulldown = pulldown;
    openPulldownBoundary = pulldownBoundary;
    openPulldownBoundaryBuffer = pulldownBoundaryBuffer;
    openPulldownShadow = pulldownShadow;
    openPulldownFrame = pulldownFrame;
    openMenuButton = menuButton;

  } else {
    addClassModifier( menuButton, "Hover" );
  }      
}
      
/*
 * Called when user moves outside the button
 */
function outMenuButton(menuButton) {
  if (!openPulldown) {
    removeClassModifier( menuButton );
  }
}

/*
 * Close an eventual open pulldown
 */
function closeMenus() {
  if (openPulldown) {
    openPulldown.style.visibility = "hidden";
    openPulldownBoundary.style.visibility = "hidden";
    openPulldownBoundaryBuffer.style.visibility = "hidden";
    openPulldownShadow.style.visibility = "hidden";
    openPulldownFrame.style.visibility = "hidden"
    removeClassModifier( openMenuButton );
    /* ???? */
    openPulldown = null;
    openPulldownBoundary = null;
    openPulldownBoundaryBuffer = null;
    openPulldownShadow = null;
    openPulldownFrame = null;
    openMenuButton = null;
  }      
}

/*
 * External click events which are not caught anywhere else end up here
 * We use this to close an open pulldown when the user clicks elsewhere.
 */
function defaultClickHandler(e) {
  if (openPulldown){
    /*
     * if the click happened outside an open pulldown, close it.
     */
    e = e ? e : event;
    x = e.clientX;
    y = e.clientY;
    if ( !isInside( openPulldown, x, y ) && 
         !isInside( openPulldown.menuButton, x, y ) ){
      closeMenus();
    }
  }
}

function outPulldown(pulldown) {
  closeMenus();
}

function overPulldownOption(option) {
  if (isButtonDisabled(option)){
    return false;
  }

  checkImage = option.firstChild.firstChild.firstChild.firstChild.firstChild;
  checkImageSplit = checkImage.src.split("/");
  if ( checkImageSplit[checkImageSplit.length - 1] == "check.gif" ) {
    whiteSrc = checkImage.src = getCheckWhite().src;
  }

  addClassModifier( option, "Hover" );
  addClassModifier(
    option.firstChild.firstChild.lastChild.lastChild.lastChild, "Hover");
  addClassModifier(
    option.firstChild.firstChild.lastChild.lastChild.firstChild, "Hover");
}
      
function outPulldownOption(option) {
  if (isButtonDisabled(option)){
    return false;
  }
  checkImage = option.firstChild.firstChild.firstChild.firstChild.firstChild;
  checkImageSplit = checkImage.src.split("/");
  if ( checkImageSplit[checkImageSplit.length - 1] == "check_white.gif" ) {
    blackSrc = checkImage.src = getCheck().src;
  }

  removeClassModifier(
    option.firstChild.firstChild.lastChild.lastChild.lastChild, "Hover");
  removeClassModifier(
    option.firstChild.firstChild.lastChild.lastChild.firstChild, "Hover");
  removeClassModifier( option );
}

/*
 * Return true if the Button/Option has been marked disabled.
 */
function isButtonDisabled( button ){
  return (button.getAttribute( "disabled" ) == "1");
}

/*
 * Return true if the Action is selected (has checkmark to left)
 */
function doesActionHaveSelected( action ){
  return (action.selected == true);
}

/*
 * Return true if the Action has a shortcut (like "Ctrl+A" or "Shift+F1")
 */
function doesActionHaveShortcut( action ){
  if ( !action.shortcut ) {
    return false;
  }
  else {
    return true;
  }
}

/*
 * Execute the menu action associated with given object (button or option)
 * Invoked via onclick="execMenuAction(this)"
 */
function execMenuAction( obj ){
  closeMenus();
  if (!isButtonDisabled(obj)){
    actionCode = obj.menuAction;
    menuCode = menuRegistry.actionMenus[actionCode];
    menu = menuRegistry.getMenu(menuCode);
    action = menu.actions[actionCode];
    actionFunc = action.func;

    if (actionFunc){
      actionFunc( actionCode );
    } else {
      /* should not reach here under normal circumstances */
      alert( "Action " + action + " has not been defined" );
    }

    if (action.disableOnClick) {
      disableMenuAction(action);
    }
  }
}

function execBottomAction( obj ) {
  actionCode = obj.menuAction;
  groupCode = buttonbarRegistry.actionGroups[actionCode];

  group = buttonbarRegistry.getGroup(groupCode);
  var action = group.actions[actionCode];
  var actionFunc = action.func;

  if (actionFunc){
    actionFunc( actionCode );
    if (action.disableOnClick) {
      disableMenuAction(action);
    }
  } else {
    /* should not reach here under normal circumstances */
    alert( "Action " + action + " has not been defined" );
  }
}

function setStateForSelection( num_selected ) {
  for (menuCode in menuRegistry.menus) {
    var menu = menuRegistry.menus[menuCode];
    doStateSwitching(menu, num_selected);
  }

  for (groupCode in buttonbarRegistry.groups) {
    var group = buttonbarRegistry.groups[groupCode];
    doStateSwitching(group, num_selected);
  }
}


/* Helpers for setStateForSelection.  Yes I know they don't need to be
   two separate functions, but for readability I want them this
   way. */
function doStateSwitching(obj, num_selected) {
  if (num_selected == 0) {
    enableByLimit(NONE_OR_ONE, obj);
    disableByLimit(ONLY_ONE, obj);
    disableByLimit(ONE_OR_MORE, obj);
    disableByLimit(MORE_THAN_ONE, obj);
  } else if (num_selected == 1) {
    enableByLimit(ONLY_ONE, obj);
    enableByLimit(ONE_OR_MORE, obj);
    enableByLimit(NONE_OR_ONE, obj);
    disableByLimit(MORE_THAN_ONE, obj);
  } else if (num_selected > 1) {
    enableByLimit(ONE_OR_MORE, obj);
    enableByLimit(MORE_THAN_ONE, obj);
    disableByLimit(ONLY_ONE, obj);
    disableByLimit(NONE_OR_ONE, obj);
  }
}

function enableByLimit( limit, obj ) {
  actions = obj.actionLimits[limit];
  if (actions) {
    for (i = 0; i < actions.length; i++) {
      actionCode = actions[i];
      enableMenuAction(actionCode);
    }
  }
}

function disableByLimit( limit, obj ) {
  actions = obj.actionLimits[limit];
  if (actions) {
    for (i = 0; i < actions.length; i++) {
      actionCode = actions[i];
      disableMenuAction(actionCode);
    }
  }
}

/*
 * Disable action
 * Deactivates both menu option and toolbar button.
 * This can be called both before and after menu is rendered.
 * 
 */
function disableMenuAction( action ){
  if (!action.code) {
    /* If they didn't pass in an action object, assume they passed in
       a string. */
    menuAction = menuRegistry.getAction(action);
    if (!menuAction) {
      menuAction = buttonbarRegistry.getAction(action);
      if (!menuAction) {
        /* The action doesn't exist!  So don't do anything. */
        return;
      }
      fromMenubar = false;
    }
    else {
      /* this is a menubar element */
      fromMenubar = true;
    }
    action = menuAction;
  }

  action.disabled = true;

  /* disable associated buttons if menu is displayed already */
  function updateButton( button ){
    button.setAttribute( "disabled", 1 );
    addClassModifier( button, "Disabled" );
    try {
      button.firstChild.firstChild.firstChild.childNodes[1].style.color = "GrayText";
    } catch (e) {
    }
  }

  updateActionButtons( action, updateButton );
}

/*
 * Enable action (reverses the effect of disableMenuAction)
 */
function enableMenuAction( action ){
  if (!action.code) {
    /* If they didn't pass in an action object, assume they passed in
       a string. */
    menuAction = menuRegistry.getAction(action);
    if (!menuAction) {
      menuAction = buttonbarRegistry.getAction(action);
      if (!menuAction) {
        /* The action doesn't exist!  So don't do anything. */
        return;
      }
    }
    action = menuAction;
  }

  action.disabled = false;

  /* enable associated buttons if menu is displayed already */
  function updateButton( button ){
    button.removeAttribute( "disabled" );
    removeClassModifier( button, "Disabled" );
    try {
      button.firstChild.firstChild.firstChild.childNodes[1].style.color = "ButtonText";
    } catch (e) {
    }

  }

  updateActionButtons( action, updateButton );
}

/*
 * Enable a menu item's selection 
 * (reverses the effect of disableMenuActionSelected)
 */
function enableMenuActionSelected( action ){
  if (!action.code) {
    /* If they didn't pass in an action object, assume they passed in
       a string. */
    menuAction = menuRegistry.getAction(action);
    if (!menuAction) {
      menuAction = buttonbarRegistry.getAction(action);
      if (!menuAction) {
        /* The action doesn't exist!  So don't do anything. */
        return;
      }
    }
    action = menuAction;
  }

  /* enable associated buttons if menu is displayed already */
  function updateButton( button ){
    /* swap the src and lowsrc of the image. that long path is due to
       a lack of unique id's to call */
    checkImage = button.firstChild.firstChild.firstChild.firstChild.firstChild;
    /* store the image locations so we can swap */
    emptyImgSrc = checkImage.getAttribute( 'src' );
    selectedImgSrc = checkImage.getAttribute( 'lowsrc' );
    /* do the actual swapping */
    checkImage.setAttribute( 'src', selectedImgSrc );
    checkImage.setAttribute( 'lowsrc', emptyImgSrc );
  }

  action.selected = true;
  updateActionButtons( action, updateButton );
}

/*
 * Disable a menu item's selection 
 * (reverses the effect of enableMenuActionSelected)
 */
function disableMenuActionSelected( action ){
  if (!action.code) {
    /* If they didn't pass in an action object, assume they passed in
       a string. */
    menuAction = menuRegistry.getAction(action);
    if (!menuAction) {
      menuAction = buttonbarRegistry.getAction(action);
      if (!menuAction) {
        /* The action doesn't exist!  So don't do anything. */
        return;
      }
    }
    action = menuAction;
  }

  /* enable associated buttons if menu is displayed already */
  function updateButton( button ){
    /* swap the src and lowsrc of the image. that long path is due to
       a lack of unique id's to call */
    checkImage = button.firstChild.firstChild.firstChild.firstChild.firstChild;
    /* store the locations of the images so we can swap */
    emptyImgSrc = checkImage.getAttribute( 'src' );
    selectedImgSrc = checkImage.getAttribute( 'lowsrc' );
    /* do the actual swapping */
    checkImage.setAttribute( 'src', selectedImgSrc );
    checkImage.setAttribute( 'lowsrc', emptyImgSrc );
  }

  action.selected = false;
  updateActionButtons( action, updateButton );
}

function hideMenuAction( action ) {
  var menuOption = document.getElementById(action + "_DIV");
  var toolButton = document.getElementById(action + "_BUTTON");
  var toolBottom = document.getElementById(action + "_BOTTOM");

  if (menuOption) {
    var pulldown = menuOption.parentNode;
    var prev = menuOption.previousSibling;
    var next = menuOption.nextSibling;
    
    menuOption.style.display = "none";

    var lastVisible;
    for (var i = 0; i < pulldown.childNodes.length; i++) {
      var optionDiv = pulldown.childNodes[i];
      if (!lastVisible && optionDiv.nodeName == "HR") {
        optionDiv.style.display = "none";
      } else if (lastVisible && lastVisible.nodeName == "HR" && optionDiv.nodeName == "HR") {
        optionDiv.style.display = "none";
      }

      if (optionDiv.style.display != "none") {
        lastVisible = optionDiv;
      }
    }

    if (lastVisible && lastVisible.nodeName == "HR") {
      lastVisible.style.display = "none";
    }

    var shadow = pulldown.previousSibling.previousSibling.previousSibling;
    var iframe = shadow.previousSibling;

    shadow.style.height = pulldown.offsetHeight;
    iframe.style.height = pulldown.offsetHeight;

    shadow.style.width = pulldown.offsetWidth;
    iframe.style.width = pulldown.offsetWidth;
  }
  if (toolButton) {
    toolButton.style.display = "none";
  }

  if (toolBottom) {
    toolBottom.style.display = "none";
  }
}

function showMenuAction( action ) {
  var menuOption = document.getElementById(action + "_DIV");
  var toolButton = document.getElementById(action + "_BUTTON");
  var toolBottom = document.getElementById(action + "_BOTTOM");

  if (menuOption) {
    var pulldown = menuOption.parentNode;
    menuOption.style.display = "block";

    for (var i = 0; i < pulldown.childNodes.length; i++) {
      var optionDiv = pulldown.childNodes[i];

      if (optionDiv.nodeName == "HR") {
        var prev = optionDiv.previousSibling;
        var next = optionDiv.nextSibling;

        if (prev && prev.style.display != "none" && next && next.style.display != "none") {
          optionDiv.style.display = "block";
        }
      }
    }

    var shadow = pulldown.previousSibling.previousSibling.previousSibling;
    var iframe = shadow.previousSibling;

    shadow.style.height = pulldown.offsetHeight;
    iframe.style.height = pulldown.offsetHeight;

    shadow.style.width = pulldown.offsetWidth;
    iframe.style.width = pulldown.offsetWidth;
  }

  if (toolButton) {
    toolButton.style.display = "inline";
  }
  if (toolBottom) {
    toolBottom.style.display = "inline";
  }
}

/*
 * Add a menu item's shortcut  
 * (can be removed with removeMenuActionShortcut)
 */
function addMenuActionShortcut( action, shortcut ){
  if (!action.code) {
    /* If they didn't pass in an action object, assume they passed in
       a string. */
    menuAction = menuRegistry.getAction(action);
    if (!menuAction) {
      menuAction = buttonbarRegistry.getAction(action);
      if (!menuAction) {
        /* The action doesn't exist!  So don't do anything. */
        return;
      }
    }
    action = menuAction;

  }

  /* enable associated buttons if menu is displayed already */
  function updateButton( button ){
    lastTD = button.firstChild.firstChild.firstChild.lastChild;

    lastTD.firstChild.appendChild( 
                                   document.createTextNode( action.shortcut ) 
                                 );
    lastTD.firstChild.style.display = "inline";
    // not sure why this works better, but without it, the div acts like it has
    // a width of 100%, even though we set it to be 40 in the css
    lastTD.firstChild.style.width = "40px";
  }

  action.shortcut = shortcut;
  updateActionButtons( action, updateButton );
}

/*
 * Remove a menu item's shortcut  
 * (removes the effect of addMenuActionShortcut)
 */
function removeMenuActionShortcut( action ){
  if (!action.code) {
    /* If they didn't pass in an action object, assume they passed in
       a string. */
    menuAction = menuRegistry.getAction(action);
    if (!menuAction) {
      menuAction = buttonbarRegistry.getAction(action);
      if (!menuAction) {
        /* The action doesn't exist!  So don't do anything. */
        return;
      }
    }
    action = menuAction;
  }

  /* enable associated buttons if menu is displayed already */
  function updateButton( button ){
    /* get the children of the button, and remove child text node of
     *  the 2nd child of button, also known as MenuShortcut */
    lastTD = button.firstChild.firstChild.firstChild.lastChild;

    if ( lastTD.firstChild.hasChildNodes() ) {
      lastTD.firstChild.removeChild( lastTD.firstChild.firstChild );
    }
    lastTD.firstChild.style.display = "none";
  }

  action.shortcut = null;
  updateActionButtons( action, updateButton );
}

function actionExistsAndAllowed( action ){
  /* This function is to check to see if an action exists, and the user
     has the proper access to the action. This was created to check to see
     if the delete button was on the page and allowed to use due to the
     issue where julie deleted all of someone else's KB entries. Note that 
     the security risk has been patched in the pylets of all the applications
     and this is just a UI precaution and to provide feedback to the user. */
 
  if (!action.code) {

    /* If they didn't pass in an action object, assume they passed in
       a string. */
    menuAction = menuRegistry.getAction(action);
    if (!menuAction) {
      /* the menuAction isn't in the menuRegistry, keep testing */
      menuAction = buttonbarRegistry.getAction(action);
      if (!menuAction) {
        /* since we didn't find the menuAction in the menuRegistry or the
           buttonbarRegistry, we can assume it's not on the page */
        return false;
      }
    }
  
  } // end if( !action.code )
  
  /* at this point we know that we have the action, and we can test it */
  if ( !hasAccess( menuAction.displayLimit ) ) {
    /* the user does not have access to the delete, even though it is 
       physically on the page (note: even though it my be on the page with 
       functioning code, it will not be drawn by the template if the user
       doesn't have the right access */
    return false;
  } 
  if ( menuAction.disabled ) {
    /* even though the user has access and the button is present, it might
       be disabled (greyed out) so we have to verify that deleting is okay */
    return false;
  }
  
  /* if we got here, nothing failed, so return true for success */
  return true;
}

/*
 * Helper function for enableMenuAction/disableMenuAction
 * Add/remove modifier to a set of buttons associated with an action
 */
function updateActionButtons( action, callbackFunc ){
  if (action.menuOption) {
    callbackFunc(action.menuOption);
  }

  if (action.toolButton) {
    callbackFunc(action.toolButton);
  }

  /* not every action is a menuOption or a toolButton */
}

function hasAccess(actionAccess) {
  /* Check for access control */

  if (actionAccess == undefined || menuAccess == undefined) {
    return true;
  } else if (menuAccess == -1) {
    return false;
  } else if (menuAccess < actionAccess) {
    return false;
  } else {
    return true;
  }
}

showUserIcon = true;

function noUserIcon() {
  showUserIcon = false;
}

// ####### breadcrumb.js #######
// Functions for the use of breadcrumb navigation bar

/* Store the breadcrumb data in these two arrays */
var bcTitles = new Array();
var bcUrls   = new Array();
var bcCallback;

function traverseForwards(title, url, winSize) {
  /* Get the last URL in the list */
  saveArgs();
  var newURL = url.split('|').pop();
  
  /* - Add the new title and new url to arrays */
  bcTitles.push(title);
  bcUrls.push(url);

  /* - Parse the titles and urls arrays */
  strTitles =  bcTitles.join('|') ;
  strUrls   = bcUrls.join('|');

  /* - Reset the arguments in case they go click-happy */
  resetArgs();

  /* - Append them as arguments to the new url */
  newURL = addToURL(newURL, "titles", strTitles);
  newURL = addToURL(newURL, "urls", strUrls);

  /* - Open the new URL */
  if (winSize) {
    openWindow(winSize, newURL);
  } else {
    document.location.href = newURL;
  }
  return false;
}

 function traverseBackwards(winSize) {
  /* - Remove the last element of the titles and urls arrays */
  saveArgs();
  bcTitles.pop();
  bcUrls.pop();
    
  /* - Parse the titles and urls arrays */
  var strTitles = bcTitles.join('|');
  var strUrls   = bcUrls.join('|');

  /* - Append them as arguments to the last url in urls */
  var newURL = bcUrls[bcUrls.length - 1];
  newURL = addToURL(newURL, "titles", strTitles);
  newURL = addToURL(newURL, "urls", strUrls);

  /* - Reset the arguments in case they go click-happy */
  resetArgs();

  /* - Open the new URL */
  if (winSize) {
    openWindow(winSize, newURL);
  } else {
    document.location.href = newURL;
  }
}

function traverseToIndex(idx, winSize) {
  /* - Truncate titles and urls arrays at index idx. */
  saveArgs();
  bcTitles = bcTitles.slice(0, idx);
  bcUrls   = bcUrls.slice(0, idx);
  
  /* - Parse the titles and urls arrays */
  var strTitles = bcTitles.join('|');
  var strUrls   = bcUrls.join('|');

  /* - Append them as arguments to the last url in urls */
  var newURL = bcUrls[bcUrls.length - 1];
  newURL = addToURL(newURL, "titles", strTitles);
  newURL = addToURL(newURL, "urls", strUrls);

  /* - Reset the arguments in case they go click-happy */
  resetArgs();

  /* Call the callback if it exists */
  if (bcCallback != undefined) {
    bcCallback(idx);
  }

  /* - Open the new URL */
  if (winSize) {
    openWindow(winSize, newURL);
  } else {
    document.location.href = newURL;
  }
}

function traverseSideways(title, url, winSize) {
  /* This function gets used when you're not changing your depth, but
     you're changing the last breadcrumb */

  /* Replace the last title and url with the new title and url */
  saveArgs();
  depth = bcTitles.length - 1;
  bcTitles[depth] = title;
  bcUrls[depth]   = url;
  
  /* Parse the titles and urls arrays */
  var strTitles = bcTitles.join('|');
  var strUrls   = bcUrls.join('|');

  /* Append them as arguments to the new url */
  var newURL = addToURL(url, "titles", strTitles);
  newURL     = addToURL(newURL, "urls", strUrls);

  /* - Reset the arguments in case they go click-happy */
  resetArgs();

  /* Open the new URL */
  if (winSize) {
    openWindow(winSize, newURL);
  } else {
    document.location.href = newURL;
  }
}

function traverseBackAndForth(depth, titles, urls, winSize) {
  /* This one is for traversing backwards a few steps, then forwards */

  /* Get the last URL in the list */
  saveArgs();
  var newURL = urls.split('|');
  newURL = newURL.pop();

  /* - Add the new title and new url to arrays */
  bcLength = bcTitles.length;
  depth = bcLength - depth;

  bcTitles = bcTitles.slice(0, depth);
  bcUrls   = bcUrls.slice(0, depth);

  bcTitles.push(titles);
  bcUrls.push(urls);
  
  /* Parse the titles and urls arrays */
  var strTitles = bcTitles.join('|');
  var strUrls   = bcUrls.join('|');

  /* - Append them as arguments to the new url */
  newURL = addToURL(newURL, "titles", strTitles);
  newURL = addToURL(newURL, "urls", strUrls);

  /* - Reset the arguments in case they go click-happy */
  resetArgs();

  /* - Open the new URL */
  if (winSize) {
    openWindow(winSize, newURL);
  } else {
    document.location.href = newURL;
  }
}

function registerBreadcrumbCallback(callback) {
  bcCallback = callback;
}

function addBorder(event) {
  var obj = this;

  if (window.event && window.event.srcElement) {
    var obj = window.event.srcElement;
    if (obj.nodeName != "BUTTON") {
      obj = obj.parentNode;
    }
  }

  if (ie) {
    removeClassModifier(obj, "IEIconButton");
  } else {
    removeClassModifier(obj, "IconButton");
  }
}

function removeBorder(event) {
  var obj = this;

  if (window.event && window.event.srcElement) {
    var obj = window.event.srcElement;
    if (obj.nodeName != "BUTTON") {
      obj = obj.parentNode;
    }
  }

  if (ie) {
    addClassModifier(obj, "IEIconButton");
  } else {
    addClassModifier(obj, "IconButton");
  }
}

/* ---------------------------
 * Desktop in the Sky Top Menu
 * ---------------------------
 */

var weekdays = new Array("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday");

// For keeping track of what submenu is open at the moment.
var openSubMenuId;

// For hiding the menu shortly after the mouse leaves it.
var hideMenuTimer;

function drawDesktopMenu() {
  var menuRequest = AJAXRequest(realDrawDesktopMenu);
  var menuQuery = "/dashboard/ajax_menu_data.pyt";

  makeAJAXCall(menuRequest, menuQuery, true);
}

function realDrawDesktopMenu(data) {
  var AppMenuButton = document.getElementById("AppMenuButton");
  var Toolbar = document.getElementById("SS_Toolbar");
  var PB = document.getElementById("PageBody");
  var FT = document.getElementById("FixedTop");
  var SC = document.getElementById("ScrollableContent");
  var LauncherBar = document.getElementById("SS_LauncherBar");
  if (ie) {
    Toolbar.style.display = "block";
  } else {
    Toolbar.style.display = "table";
  }

  var menuItems = data.Row1.Left;

  var AppMenu = document.createElement("div");
  AppMenu.className = "SS_MenuContainer";
  //var AppMenu = document.createElement("ul");
  //AppMenu.className = "cm_default";
  AppMenu.id = "AppMenu";
  //AppMenu.style.top = "69px";
  AppMenu.style.left = "5px";
  AppMenu.style.zIndex = 99999;
  AppMenu.style.display = "none";
  PB.appendChild(AppMenu);

  var AppMenuFrame = document.createElement("div");
  AppMenuFrame.className = "SS_MenuContainerFrame TransHeavy";
  AppMenuFrame.id = "AppMenuFrame";
  PB.appendChild(AppMenuFrame);

  /*var AppMenuBG = document.createElement("div");
  AppMenuBG.id = "AppMenuBG";
  AppMenuBG.className = "SS_MenuContainerBG TransHeavy";
  AppMenuBG.style.top = "25px";
  AppMenuBG.style.left = "5px";
  AppMenuBG.style.display = "none";
  PB.appendChild(AppMenuBG);*/
  
  ss_attachEvent(AppMenu, "mouseover", clearHideMenuTimer);
  ss_attachEvent(AppMenu, "mouseout", timedHideMenu);

  if (data.Row1) {
    addToMenu(AppMenu, data.Row1.Heading[0].name, data.Row1.Left);
  }

  if (data.Row2) {
    addToMenu(AppMenu, data.Row2.Heading[0].name, data.Row2.Left);
  }

  if (data.Row3) {
    addToMenu(AppMenu, data.Row3.Heading[0].name, data.Row3.Left);
  }

  if (data.showNodeAdminButton) {
    var nodeAdminButton = addToMenu(AppMenu, "Node Admin", null, launchURL);
    nodeAdminButton.ss_url = data.nodeAdminUrl;
    nodeAdminButton.ss_title = "Node Admin";
    ss_attachEvent(nodeAdminButton, "click", hideMenu);
  }

  if (data.showAdminButton) {
    var adminButton = addToMenu(AppMenu, "Admin", null, launchURL);
    adminButton.ss_url = data.adminUrl;
    adminButton.ss_title = "Admin";
    ss_attachEvent(adminButton, "click", hideMenu);
  }

  //addToMenu(AppMenu, "Desktop Configuration...", null, showDesktopConfig);
  addToMenu(AppMenu, "AppStore...", null, loadAppStore);
  addToMenu(AppMenu, "Create Shortcut...", null, showNewShortcut);
  addToMenu(AppMenu, "Place a file on desktop...", null, showNewFile);
  addToMenu(AppMenu, "Trash", null, openDesktopTrash);
  addToMenu(AppMenu, "Options...", null, showOptionsPopup);
  //addToMenu(AppMenu, "Log Out " + uName, null, defaultExitLogout);

  ss_attachEvent(AppMenuButton, "click", showMenu);
  //drawTime();
  //setInterval(drawTime, 1000);

  // Should already be absolute, but for some reason it isn't.  So we set it
  // here.
  SC.style.position = "absolute";
  SC.style.top = FT.offsetHeight;

  // Add the + tab.
  var plusTab = document.getElementById("SS_PlusTab");
  var plusTabLink = plusTab.firstChild;

  if (plusTab) {
    plusTab.style.display = "block";
    plusTab.parentNode.removeChild(plusTab);
    plusTabLink.style.padding = "0.15em 1em" // Matches other tabs.
    FT.appendChild(plusTab);
  }

  // Add the permanent tabs.
  var permTabs = document.getElementById("SS_PermanentTabs");
  
  if (permTabs) {
    permTabs.parentNode.removeChild(permTabs);
    FT.appendChild(permTabs);
  }

  // Resize and reposition everything.
  if (plusTab || permTabs) {
    resizeTabBar();
  }

  for (var i = 0; i < data["launchers"].length; i++) {
    var launcher = data["launchers"][i];
    var launcherButton = document.createElement("img");
    launcherButton.src = launcher["icon"];
    launcherButton.border = 0;
    launcherButton.height = 20;
    launcherButton.width = 20;
    launcherButton.ss_target = launcher["target"];
    launcherButton.ss_name = launcher["name"];
    launcherButton.title = launcher["description"];
    launcherButton.className = "SS_LauncherButton";

    ss_attachEvent(launcherButton, "click", openLauncher);
    ss_attachEvent(launcherButton, "dblclick", openLauncher);
    
    LauncherBar.appendChild(launcherButton);
  }

  $('#SS_LauncherBar img').tooltip({ delay: 0, showURL: false, fade: 100 });
}

function openLauncher() {
  var launcher = this || window.event.srcElement;
  var target = launcher.ss_target;
  var name = launcher.ss_name;

  openWindow("xx-large/large", target, name, false);
}

function addToMenu(menu, displayName, submenu, customClick) {
  var AppMenuItem = document.createElement("div");
  //var AppMenuItem = document.createElement("li");
  var PB = document.getElementById("PageBody");
  AppMenuItem.innerHTML = displayName;
  AppMenuItem.className = "SS_MenuItem";
  menu.appendChild(AppMenuItem);
  ss_attachEvent(AppMenuItem, "mouseover", highlightMenuItem);

  if (customClick) {
    if (menu.id == "AppMenu") {
      ss_attachEvent(AppMenuItem, "mouseover", hideSubMenu);
    }
    ss_attachEvent(AppMenuItem, "click", customClick);
  }

  if (submenu) {
    var SubMenu = document.createElement("div");
    //var SubMenu = document.createElement("ul");
    SubMenu.className = "SS_MenuContainer";
    //SubMenu.className = "jeegoocontext cm_default";
    SubMenu.id = displayName + "SubMenu";
    SubMenu.style.top = "60px";
    SubMenu.style.display = "none";
    SubMenu.style.zIndex = 99999;

    var SubMenuFrame = document.createElement("iframe");
    SubMenuFrame.className = "SS_MenuContainerFrame TransHeavy";
    SubMenuFrame.id = displayName + "SubMenuFrame";

    //var SubMenuBG = document.createElement("div");
    //SubMenuBG.className = "SS_MenuContainerBG TransHeavy";
    //SubMenuBG.id = displayName + "SubMenuBG";

    AppMenuItem.subMenuId = SubMenu.id;

    ss_attachEvent(SubMenu, "mouseover", clearHideMenuTimer);
    ss_attachEvent(SubMenu, "mouseout", timedHideMenu);

    var SubMenuIcon = document.createElement("img");
    SubMenuIcon.src = imagesURL + "/templates/menu_submenu_arrow.png";
    SubMenuIcon.align = "middle";
    SubMenuIcon.style.position = "absolute";
    SubMenuIcon.style.float = "right";
    SubMenuIcon.style.right = "5";
    //SubMenuIcon.className = "submenu";
    AppMenuItem.appendChild(SubMenuIcon);

    PB.appendChild(SubMenu);
    PB.appendChild(SubMenuFrame);
    //PB.appendChild(SubMenuBG);

    for (var i = 0; i < submenu.length; i++) {
      var menuItem = submenu[i];
      var menuButton = addToMenu(SubMenu, menuItem.name, null, launchURL);
      menuButton.ss_url = menuItem.url;
      menuButton.ss_title = menuItem.name;
      ss_attachEvent(menuButton, "click", hideMenu);
    }

    if (!customClick) {
      ss_attachEvent(AppMenuItem, "mouseover", showSubMenu);
    }
  }

  return AppMenuItem
}

function drawTime() {
  var timeBox = document.getElementById("TimeBox");
  var now = new Date();

  var ampm = "AM";
  var hour = now.getHours();
  var minute = now.getMinutes();
  var sec = now.getSeconds();
  var day = now.getDay();

  if (hour > 12) {
    hour -= 12;
    ampm = "PM";
  } else if (hour == 0) {
    hour = 12;
  }

  if (minute.toString().length == 1) {
    minute = "0" + minute;
  }

  /* if (sec % 2 == 1) {
    displayTime = weekdays[day] + " " + hour + ":" + minute + " " + ampm;
  } else {
    displayTime = weekdays[day] + " " + hour + " " + minute + " " + ampm;
  } */
  displayTime = weekdays[day] + " " + hour + ":" + minute + " " + ampm;
  timeBox.innerHTML = displayTime;
}

function showMenu() {
  var AppMenu = document.getElementById("AppMenu");
  var AppMenuFrame = document.getElementById("AppMenuFrame");
  //var AppMenuBG = document.getElementById("AppMenuBG");
  var AppMenuButton = document.getElementById("AppMenuButton");

  AppMenu.style.display = "block";
  AppMenuFrame.style.display = "block";
  AppMenuFrame.style.height = AppMenu.offsetHeight - 10;
  //AppMenuBG.style.height = AppMenu.offsetHeight - 10;
  AppMenuButton.firstChild.src = imagesURL + "templates/menu_btn_rollover.jpg";

  ss_detachEvent(AppMenuButton, "click", showMenu);
  ss_attachEvent(AppMenuButton, "click", hideMenu);
}

function hideMenu() {
  var AppMenu = document.getElementById("AppMenu");
  var AppMenuFrame = document.getElementById("AppMenuFrame");
  //var AppMenuBG = document.getElementById("AppMenuBG");
  var AppMenuButton = document.getElementById("AppMenuButton");

  AppMenu.style.display = "none";
  AppMenuFrame.style.display = "none";
  //AppMenuBG.style.display = "none";
  AppMenuButton.firstChild.src = imagesURL + "templates/menu_btn_off.jpg";

  ss_detachEvent(AppMenuButton, "click", hideMenu);
  ss_attachEvent(AppMenuButton, "click", showMenu);
  hideSubMenu();
}

function showSubMenu() {
  var itemClicked = this || window.event.srcElement;
  if (itemClicked == window) itemClicked = window.event.srcElement;
  var SubMenuId = itemClicked.subMenuId;
  var SubMenu = document.getElementById(SubMenuId);
  var SubMenuFrame = document.getElementById(SubMenuId + "Frame");
  //var SubMenuBG = document.getElementById(SubMenuId + "BG");
  var AppMenu = document.getElementById("AppMenu");

  hideSubMenu();
  SubMenu.style.left = AppMenu.offsetLeft + AppMenu.offsetWidth;
  SubMenu.style.top = AppMenu.offsetTop + itemClicked.offsetTop;
  SubMenu.style.display = "block";
  SubMenuFrame.style.left = AppMenu.offsetLeft + AppMenu.offsetWidth;
  SubMenuFrame.style.top = SubMenu.offsetTop;
  SubMenuFrame.style.height = SubMenu.offsetHeight - 10;
  SubMenuFrame.style.display = "block";
  //SubMenuBG.style.left = AppMenu.offsetLeft + AppMenu.offsetWidth;
  //SubMenuBG.style.top = SubMenu.offsetTop;
  //SubMenuBG.style.height = SubMenu.offsetHeight - 10;
  //SubMenuBG.style.display = "block";

  openSubMenuId = SubMenuId;
}

function hideSubMenu() {
  if (openSubMenuId) {
    var SubMenu = document.getElementById(openSubMenuId);
    var SubMenuFrame = document.getElementById(openSubMenuId + "Frame");
    //var SubMenuBG = document.getElementById(openSubMenuId + "BG");
    SubMenu.style.display = "none";
    SubMenuFrame.style.display = "none";
    //SubMenuBG.style.display = "none";
    openSubMenuId = null;
  }
}

function timedHideMenu() {
  hideMenuTimer = setTimeout("hideMenu()", 1500);
}

function clearHideMenuTimer() {
  clearTimeout(hideMenuTimer);
}

function highlightMenuItem() {
  var menuItem = this || window.event.srcElement;
  addClassModifier(menuItem, "SS_MenuItemSelected");
  ss_attachEvent(menuItem, "mouseout", unhighlightMenuItem);
}

function unhighlightMenuItem() {
  var menuItem = this || window.event.srcElement;
  removeClassModifier(menuItem, "SS_MenuItemSelected");
  ss_detachEvent(menuItem, "mouseout", unhighlightMenuItem);
}

function tabCreated(data) {
  drawNewFrameTab(data.tab.ID, data.tab.name, data.tab.target, true);
}

function createNewTab(title, url) {
  var newTabCall = new AJAXRequest(tabCreated);
  var callUrl = "ajax_new_tab.pyt?title=" + escape(title);

  if (url.indexOf("://") == -1) {
    url = "http://" + url;
  }

  callUrl += "&url=" + escape(url);

  makeAJAXCall(newTabCall, callUrl, true);
}

function launchURL() {
  var icon = this || window.event.srcElement;

  createNewTab(icon.ss_title, icon.ss_url);  
}

function showNewShortcut() {
  var openFrame = getOpenTabContent();

  try {
    openFrame.showNewShortcut();
  } catch(e) {
  }

  hideMenu();
}

function showNewFile() {
  var openFrame = getOpenTabContent();

  try {
    openFrame.showNewFile();
  } catch(e) {
  }

  hideMenu();
}

function showOptionsPopup() {
  var openFrame = getOpenTabContent();

  try {
    openFrame.showOptionsPopup();
  } catch(e) {
  }

  hideMenu();
}

function openDesktopTrash() {
  var openFrame = getOpenTabContent();

  try {
    openFrame.openDesktopTrash();
  } catch(e) {
  }

  hideMenu();
}

/* ----------------
 * Helper Functions
 * ----------------
 */

function addToURL(url, name, value) {
  value = escape(value);
  if (url.indexOf('?') == -1) {
    url += "?" + name + '=' + value;
  } else if (url.indexOf('?') == (url.length - 1)) {
    url += name + '=' + value;
  } else {
    url += "&" + name + '=' + value;
  }

  return url;
}

function saveArgs() {
  undoTitles = bcTitles.join('|');
  undoUrls   = bcUrls.join('|');
}

function resetArgs() {
  bcTitles = undoTitles.split('|');
  bcUrls   = undoUrls.split('|');
}

// ####### list.js #######
// Functions for the drawing of the list template

/* Globals */
var listKey = "";
var listOrderedBy = "";
var listShowHeaders = true;
var listMultiSelect = true;
var listDraggable = false;
var listDrawSelected = new Object();
var selectedRows = new Object();
var numSelected = 0;
var listDragging = 0;
var listDraggingContinued = 0;
var lastRow;
var rowToDrag;
var content;

var lastClicked;
var openTimeout;
var scrollInterval;
var scrollingFolders = false;

var varRegEx = /{[A-Za-z\.]+}/;

/* Objects */
selectionCallbacks = new Object();

columnDefs = new Object();
function columnDef(name, title, orderBy, description, format, linkTitle,
                   linkType, linkTarget, linkScript, width, align, valign,
                   headerAlign, fieldType, indent, bgColor, textColor) {
  this.name = name;
  this.title = title;
  this.orderBy = orderBy;
  this.description = description;
  this.format = format;
  this.linkTitle = linkTitle;
  this.linkType = linkType;
  this.linkTarget = linkTarget;
  this.linkScript = linkScript;
  this.width = width;
  this.align = align;
  this.valign = valign;
  this.headerAlign = headerAlign;
  this.fieldType = fieldType;
  this.indent = indent;
  this.bgColor = bgColor;
  this.textColor = textColor;
}

var listData = new Object();
var listOrder = new Array();
var listFunctions = new Object();
var listOrderByLinks = new Object();

/* Globals for drawing the list */
var linkTemplate;
var scriptLinkTemplate;
var headerLinkTemplate;
var mailtoLinkTemplate;
var imageTemplate;
var cellTemplate       = document.createElement("td");
cellTemplate.className = "ListCell";

var newTN              = document.createTextNode("Cell");
cellTemplate.appendChild(newTN);

/* Just a blank constructor.  We'll set values on it in the
   transformation process and it becomes our data object. */
function dataObj() {};

/* Functions */
function addListData(dataObject, dataKey, value) {
  if (dataObject[dataKey]) {
    storedVal = dataObject[dataKey];
    if (storedVal.push) {
      dataObject[dataKey].push(value);
    } else {
      dataObject[dataKey] = new Array(storedVal, value);
    }
  } else {
    dataObject[dataKey] = value;
  }
}

function addListRow(container, newRow, data, insertTop, pos) {
  newRow.style.visibility = "visible";
  newRow.key = data[listKey];
  newRow.idx = i;
  newRow.id = "List_" + data[listKey];

  if (i % 2 == 1) {
    addClassModifier(newRow, "AltBg");
  }

  ss_attachEvent(newRow, "mouseover", doHighlight);
  ss_attachEvent(newRow, "mouseout", removeHighlight);
  ss_attachEvent(newRow, "click", callDoSelect);
  ss_attachEvent(newRow, "dblclick", callDblClick);

  for (key in columnDefs) {
    column = columnDefs[key];
    newCell = cellTemplate.cloneNode(true);
    newCell.removeChild(newCell.firstChild);
    newCell.style.textAlign = column.align;
    newCell.style.verticalAlign = column.valign;

    if (column.width != "0") {
      newCell.style.width = column.width;
    }
    if (column.indent) {
      indent = data[column.indent];
      if (indent && indent != "0") {
        newCell.style.paddingLeft = indent + "em";
        newIndent = document.createElement("img");
        newIndent.src = imagesURL + "templates/indent.gif";
        newCell.appendChild(newIndent);
      }
    }
    
    if (column.bgColor) {
      var bgColor = eval("data." + column.bgColor);
    } else {
      var bgColor = "";
    }  

    if (column.textColor) {
      var textColor = eval("data." + column.textColor);
    } else {
      var textColor = "";
    }

    var displayText = getDisplayText(column, data);

    try {
      columnText = eval('data.' + column.name);
    } catch(e) {
      columnText = "";
    }
    addCells(newCell, column, displayText, columnText, bgColor, textColor);

    newRow.appendChild(newCell);
    if (listDrawSelected[newRow.key]) {
      selectRow(newRow);
    }
  }
  
  try {
    if (ajaxWebmail && (!data["FLAGS"] || !data["FLAGS"]["SEEN"])) {
      // Webmail specific hack!
      addClassModifier(newRow, "NewMessage");
    }
  } catch(e) {
    // If we aren't displaying in Webmail, do nothing!
  }

  var listBody = document.getElementById("ListBody");
  if (pos  && pos < listBody.rows.length) {
    listBody.insertBefore(newRow, listBody.rows[pos]);
  } else  if (insertTop) {
    listBody.insertBefore(newRow, listBody.firstChild);
  } else {
    listBody.appendChild(newRow);
  }
}

function addCells(newCell, column, displayText, columnText, bgColor, textColor) {
  if(displayText) {
    try {
      displayText = displayText.replace(/\\\//g, "/");
    } catch(e) {}  
  }  
  if (bgColor) {
    newCell.style.backgroundColor = bgColor;
  } else {
    newCell.style.backgroundColor = "";
  }

  if (textColor) {
    newCell.style.color = textColor;
  } else {
    newCell.style.color = "";
  }

  if (column.format == "image" && column.linkType == "href") {
    if (displayText) {
      newImg = imageTemplate.cloneNode(true);
      newImg.src = displayText;
      newImg.border = 0;
      newLink = linkTemplate.cloneNode(true);
      newLink.removeChild(newLink.firstChild);
      newLink.href = columnText;
      if (column.linkTarget) {
        newLink.target = column.linkTarget;
      }
      newLink.appendChild(newImg);
      newCell.appendChild(newLink);
    }
  } else if (column.format == "image" && column.linkType == "script") {
    if (displayText) {
      newImg = imageTemplate.cloneNode(true);
      newImg.src = displayText;
      newImg.border = 0;
      newLink = scriptLinkTemplate.cloneNode(true);
      newLink.key = newRow.key;
      newLink.columnName = column.name;
      newLink.removeChild(newLink.firstChild);
      if (column.linkTarget) {
        newLink.target = column.linkTarget;
      }
      newLink.appendChild(newImg);
      newCell.appendChild(newLink);
    }
  } else if (column.format == "image") {
    if (displayText) {
      newImg = imageTemplate.cloneNode(true);
      newImg.src = displayText;
      newCell.appendChild(newImg);
    }
  } else if (column.format == "list") {
    textTemplate = document.createTextNode("");
      //firstChild.cloneNode(true);
    brTemplate = document.createElement('br');
    if (!displayText.push) {
      displayText = new Array(displayText);
    }
    for (var j = 0; j < displayText.length; j++) {
      newText = textTemplate.cloneNode(true);
      newText.nodeValue = displayText[j];
      newCell.appendChild(newText);
      newBr = brTemplate.cloneNode(true);
      newCell.appendChild(newBr);
    }
  } else if (column.format == "textInput") {
    input = document.createElement('input');
    input.type = "text";
    input.value = displayText;
    input.style.width="100%";
    input.name = column.name + "_" + newRow.key;
    input.key = newRow.key;
    input.field = column.name;
    input.onblur = new Function("listData[this.key][this.field] = this.value;");
    newCell.appendChild(input);
  } else if (column.linkType == "href") {
    newLink = linkTemplate.cloneNode(true);
    newLink.href = columnText;
    newLink.url = newLink.href;
    if (column.linkTarget) {
      newLink.target = column.linkTarget;
    }
    newLink.firstChild.nodeValue = displayText;
    newCell.appendChild(newLink);
  } else if (column.linkType == "script") {
    newLink = scriptLinkTemplate.cloneNode(true);
    newLink.firstChild.nodeValue = displayText;
    newLink.key = newRow.key;
    newLink.columnName = column.name;
    if (column.linkTarget) {
      newLink.target = column.linkTarget;
    }
    newCell.appendChild(newLink);
  } else if (column.linkType == "mailto") {
    if (displayText) {
      newLink = mailtoLinkTemplate.cloneNode(true);
      newLink.href = "mailto:" + columnText;
      newLink.firstChild.nodeValue = displayText;
      newCell.appendChild(newLink);
    }  
  } else {

    if (displayText) {

      displayText = displayText;
      if (column.format == "html") {
        newCell.innerHTML = unescape(displayText);
      } else {
        textNode = document.createTextNode(displayText);
        try {
          if (ajaxWebmail) {
            newCell.style.overflow = "hidden";
            textDiv = document.createElement("nobr");
          } else {
            textDiv = document.createElement("div");
          }
        } catch(e) {
          textDiv = document.createElement("div");
        }
        
        textDiv.appendChild(textNode);
        newCell.appendChild(textDiv);
      }
    }
  }
}

function listShow(container) {
  var container      = document.getElementById(container);

  content            = getTemplate('ScrollableContent', false);
  linkTemplate       = getTemplate('Link',              false); //
  scriptLinkTemplate = getTemplate('ScriptLink',        false); //
  headerLinkTemplate = getTemplate('HeaderLink',        false); //
  mailtoLinkTemplate = getTemplate('MailtoLink',        false); //
  imageTemplate      = getTemplate('ListImage',         false); //
  
  headerRow          = document.createElement("tr");
  headerRow.className = "ListHeaderRow";

  headerTemplate     = document.createElement("th");
  headerTemplate.className = "ContentCategory";
  newTN              = document.createTextNode("Header");
  headerTemplate.appendChild(newTN);

  rowTemplate        = document.createElement("tr");
  rowTemplate.className = "ListRow";

  listHead           = document.createElement("thead");
  listHead.id        = "ListHead";
  listBody           = document.createElement("tbody");
  listBody.id        = "ListBody";

  hiddenTemplate     = getTemplate('HiddenField',       false); //
  listNoContent      = getTemplate('ListNoContent',     false);
  table              = getTemplate('ListTable',         false); //

  listHead.appendChild(headerRow);
  table.appendChild(listHead);
  table.appendChild(listBody);
  table.style.visibility = "visible";

  if (listDraggable) {
    table.onselectstart = new Function ("return false");
    table.onmousedown = new Function ("return false");
  }

  try {
    if (ajaxWebmail) {
      table.style.tableLayout = "fixed";
    }
  } catch (e) {
    // Do nothing.
  }

  container.appendChild(table);
  container.appendChild(listNoContent);

  if (listShowHeaders) {
    for (key in columnDefs) {
      column = columnDefs[key];
      newHeader = headerTemplate.cloneNode(true);
      newHeader.style.textAlign = column.headerAlign;
      newHeader.style.visibility = "visible";
      if (column.width != "0") {
        newHeader.style.width = column.width;
      }

      if (listOrderByLinks[column.orderBy]) {
        newLink = headerLinkTemplate.cloneNode(true);
        newLink.href = listOrderByLinks[column.orderBy];
        newLink.innerHTML = column.title;
        newHeader.removeChild(newHeader.firstChild);
        newHeader.appendChild(newLink);
      } else {
        newHeader.innerHTML = column.title;
      }

      if (listOrderedBy && listOrderedBy == column.orderBy) {
        addClassModifier(newHeader, "ContentCategorySelected");
      }

      headerRow.appendChild(newHeader);
    }
    headerRow.type = "header";
  }

  if (listOrder.length) {
    document.onkeydown = listKeyHandler;
    listNoContent.style.visibility = "hidden";
  } else {
    listNoContent.style.visibility = "visible";
  }
  
  for (i = 0; i < listOrder.length; i++) {
    var data = listData[listOrder[i]];

    newRow = rowTemplate.cloneNode(true);
    addListRow(container, newRow, data);
  }

  /* Default callback for when items are selected.  enableForSelected
     is defined in the menu, but since the menu gets drawn before the
     selection we have to set the callback here. */
  setSelectionCallback('MenuCallback', setStateForSelection);

  /* Call the callback to set the correct enable/disable state in case
     there were some rows that are selected to start with */
  doCallbacks();
}

function addKeysToForm(form, fieldName) {
  /* Use the default key if no field name is provided */
  if (!fieldName) {
    fieldName = listKey;
  }

  /* Clear any hidden key fields first */
  //var oldFields = form.getElementsByName(fieldName);

  var fields = new Array();
  var hiddens = form.childNodes;

  for (var i = 0; i < hiddens.length; i++) {
    var hidden = hiddens[i];
    if (hidden.name == fieldName) {
      fields.push(hidden);
    }
  }

  for (var i = 0; i < fields.length; i++) {
    form.removeChild(fields[i]);
  }

  /* Adds the selected values as hidden fields to the given form */
  for (key in selectedRows) {
    newHidden = hiddenTemplate.cloneNode(true);
    newHidden.name = fieldName;
    newHidden.value = key;
    form.appendChild(newHidden);
  }
}

function getDisplayText(column, data) {
  /* Figures out what the text that needs to be displayed in the
     column is. */
  try {
    if (column.linkTitle) {
      var displayText = expandVars(column.linkTitle, data);
    } else if (varRegEx.test(column.name)) {
      var displayText = expandVars(column.name, data);
    } else {
      var displayText = eval('data.' + column.name);
    }
  } catch(e) {
    displayText = "";
  }

  return displayText

}

function doHighlight() {
  if (window.event && window.event.srcElement) {
    realDoHighlight(window.event.srcElement);
  } else {
    realDoHighlight(this);
  }
  return true;
}

function removeHighlight() {
  if (window.event && window.event.srcElement) {
    realRemoveHighlight(window.event.srcElement);
  } else {
    realRemoveHighlight(this);
  }
}

function realDoHighlight(obj) {
  obj = getRowFromEventObj(obj);
  if (!obj) { return; }
  if (!selectedRows[obj.key]) {
    removeClassModifier(obj, "AltBg");
    addClassModifier(obj, "OverBg");
    if (listDraggable) {
      obj.onselectstart = new Function ("return false");
      obj.onmousedown = startListDrag;
      obj.onmouseup = stopListDrag;
    }
  }
}

function realRemoveHighlight(obj) {
  obj = getRowFromEventObj(obj);
  if (!obj) { return; }
  if (!selectedRows[obj.key]) {
    removeClassModifier(obj, "OverBg");
    if (obj.idx % 2 == 1) {
      addClassModifier(obj, "AltBg");
    }
    if (listDraggable) {
      ss_detachEvent(obj, "mousedown", startListDrag);
      ss_detachEvent(obj, "mouseup", stopListDrag);
    }
  }
}

function callDoSelect(event) {
  if (window.event && window.event.srcElement) {
    doSelect(window.event.srcElement.parentNode, window.event);
  } else {
    doSelect(this, event);
  }
}

function callDblClick() {
  execListAction("DOUBLE");
}
    
function getRowFromEventObj(obj) {
  while (obj.nodeName != "TR" || !obj) {
    obj = obj.parentNode;
  }

  return obj
} 

function doSelect(obj, event) {
  var control = (((window.Event) ? event.modifiers & Event.CONTROL_MASK : 0) ||
                 event.ctrlKey || event.metaKey );
  var shift   = (((window.Event) ? event.modifiers & Event.SHIFT_MASK : 0 ) || 
                 event.shiftKey );

  /* This statement is to force the frame where the object lives to be focused,
   * so that the keyhandler can get the correct input from the keyboard to
   * control the object and the objects around it. */
  window.focus();

  obj = getRowFromEventObj(obj);
  if (shift && listMultiSelect) {
    if (lastClicked) {
      if (obj.idx > lastClicked.idx) {
        start = lastClicked;
        end = obj;
      } else {
        start = obj;
        end = lastClicked;
      }

      next = start;
      while (next != end) {
        selectRow(next);
        next = next.nextSibling;
      }
      
      selectRow(end);

    }
  } else if (control) {
    if (selectedRows[obj.key]) {
      /* Toggle */
      deselectRow(obj);
    } else if (listMultiSelect) {
      selectRow(obj);
    } else {
      /* Treat it as a single click since you can't multiSelect */
      for (key in selectedRows) {
        deselectRow(selectedRows[key]);
      }
      
      selectRow(obj);
    }      
    execListAction('SINGLE');
  } else {
    /* Single click */
    for (key in selectedRows) {
      deselectRow(selectedRows[key]);
    }

    selectRow(obj);
    execListAction('SINGLE');

  }

  lastClicked = obj;
  doCallbacks();
}

function selectRowById(rowId) {
  var row = document.getElementById("List_" + rowId);
  selectRow(row);
  lastClicked = row;
  doCallbacks();
}

function deselectRowById(rowId) {
  var row = document.getElementById("List_" + rowId);
  deselectRow(row);
  doCallbacks();
}

function selectRow(row) {
  if (row ) { 
    if (!selectedRows[row.key]) {
      selectedRows[row.key] = row;
      numSelected++;
      removeClassModifier(row, "AltBg");
      removeClassModifier(row, "OverBg");
      addClassModifier(row, "SelectedBg");
    }  

    listDiv = document.getElementById("ListDiv");
    if (listDiv) {
      listDivHigth = listDiv.offsetHeight + listDiv.scrollTop - 20;
      rowTop = row.offsetTop;
      if ( rowTop > listDivHigth ) {
        listDiv.scrollTop += (rowTop - listDivHigth);
      } else if (rowTop < listDiv.scrollTop ) {
        listDiv.scrollTop -= (listDiv.scrollTop - rowTop);
      }
    }

    if (listDraggable) {
      row.onmousedown = startListDrag;
      row.onmouseup = stopListDrag;
      content.onmousemove = doListDrag;
      content.onmouseup = stopListDrag
    }
  }
}

function deselectRow(row) {
  if (selectedRows[row.key]) {
    delete selectedRows[row.key];
    numSelected--;
    removeClassModifier(row, "SelectedBg");
    if (row.idx % 2 == 1) {
      addClassModifier(row, "AltBg");
    }
    if (listDraggable) {
      ss_detachEvent(row, "mousedown", doListDrag);
      ss_detachEvent(row, "mouseup", stopListDrag);
    }
  }
}

function selectAll() {

  table = getTemplate('ListTable', false);
  rows  = table.rows;

  for (i = 1; i < rows.length; i++) {
    row = rows[i];
    selectRow(row);
  }

  window.focus();
  doCallbacks();
}

function deselectAll() {
  for (key in selectedRows) {
    row = selectedRows[key];
    deselectRow(row);
  }

  doCallbacks();
}

function setSelectionCallback(name, callback) {
  selectionCallbacks[name] = callback;
}

function removeSelectionCallback(name) {
  delete selectionCallbacks[name];
}

function doCallbacks() {
  for (name in selectionCallbacks) {
    var callback = selectionCallbacks[name];
    callback(numSelected);
  }
  if ( defaultTree ) {
    eval( defaultTree + ".inactivateFolder(" + numSelected + ")");
  } else {
    var folderName = document.getElementById(lastOpenedTreeRow + "_Name");
    if (folderName) {
      if(numSelected){
        removeClassModifier(folderName, "SelectedBg");
        addClassModifier(folderName, "SelectedInactiveBg");
      } else {
        removeClassModifier(folderName, "SelectedInactiveBg");
        addClassModifier(folderName, "SelectedBg");
      }
    }
  }  
}

function setSingleClick(func) {
  listFunctions['SINGLE'] = func;
}

function setDoubleClick(func) {
  listFunctions['DOUBLE'] = func;
}

function setDelete(func) {
  listFunctions['DELETE'] = func;
}

function setPaginate(func) {
  listFunctions['PAGINATE'] = func;
}

function setDragColumn( clName ) {
  listFunctions['DRAG_COLUMN'] = clName;
}

function getListRow( key ) {
  return listData[key];
}

function getListRowObjById( key ) {
  var listRow = document.getElementById("List_" + key);
  return listRow;
}

function  deleteListRowById( key, hideNoContent ) {
  var listRow = getListRowObjById( key );
  if (listRow) {
    var firstRow = listRow.parentNode.firstChild;
    if (listRow == firstRow && listRow.parentNode.childNodes.length > 1) {
      // Move images from first row to second row
      var secondRow = listRow.parentNode.childNodes[1];
      for (var i = 0; i < listRow.childNodes.length; i++) {
        var td = listRow.childNodes[i];
        if (td && td.childNodes.length > 0) {
          var lastObj = td.childNodes[ td.childNodes.length-1 ];
          if (lastObj && lastObj.src && lastObj.src.indexOf("pixel") != -1 ) {
            var thisImg = lastObj.cloneNode(true);
            secondRow.childNodes[i].appendChild(thisImg);
            secondRow.childNodes[i].style.width = 1;
          } 
        }
      }
    } 

    if( selectedRows[key] ) {
      numSelected --;
      delete selectedRows[key];
    }
    listRow.parentNode.removeChild(listRow);
    var keyPos = indexOf(listOrder, key);
    listOrder.splice(keyPos,1);
    delete listData[ key ];
  }  
  if ( listOrder.length == 0  && !hideNoContent ) {
    showNoContent();
  }
}

function ajaxAddDeleteListRows(containerID, ajaxData ) {
  var container = document.getElementById(containerID);
  var listBody = document.getElementById("ListBody");

  if (!ajaxData) {
    ajaxData = new Array();
  } else if (!ajaxData.push) {
    ajaxData = new Array(ajaxData);
  }

  var newItems = new Object();
  var newValues = new Array();
  var existItems = new Object();
  var listOrder_new = new Array();
  for (var i = 0; i < ajaxData.length; i++) {
    var data = ajaxData[i];
    var uid = data[listKey];
    listOrder_new.push(uid);
    if (uid && uid != "None") {
      existItems[uid] = 1;
      if (!listData[uid]) {
        //listOrder.unshift(uid);
        listData[uid] = data;
        newValues.push(uid);
        var newItem = new Object();
        newItem.uid = uid;
        newItem.data = data;
        newItem.pos = i;
        newItems[uid] = newItem;
      }  
    } 
  }
  for ( i=listOrder.length-1; i>=0; i--) {
    if ( !existItems[ listOrder[i] ] ) {
      deleteListRowById(listOrder[i]);
    }
  }

  // just to keep the order of listOrder the same as the page for selecting next message.
  // we cannot use = sign because they will be related  
  tempList = listOrder_new.join(",");
  listOrder = tempList.split(",");  

  if ( newValues.length > 0 ) {
    for ( i=0; i<newValues.length; i++ ) {
      var key = newValues[i];
      if(key) {
        var newRow = rowTemplate.cloneNode(true);
        listNoContent.style.visibility = "hidden";

        pos = newItems[key].pos ;
        if (pos < listBody.rows.length) {
          addListRow(container, newRow, newItems[key].data, true, pos);
        } else {
          addListRow(container, newRow, newItems[key].data, false);
        }  
      }
    }
  }
  messageView = 0;
  if (!ajaxData.length) {
    showNoContent();
  } else {
    updateRowColors();
  }  
  doCallbacks();
}


function getListSelection() {
  selection = new Array();
  for (key in selectedRows) {
    selection.push(key);
  }
  
  if (selection.length == 1) {
    return selection[0];
  } else {
    return selection;
  }
}

getSelection = getListSelection;

function getSelectedColumn(columnName) {
  var columnData = new Array();

  for (key in selectedRows) {
    data = listData[key];
    try {
        value = eval('data.' + columnName);
    } catch (e) {
        value = ""
    }
    columnData.push(value);
  }

  if (columnData.length == 1) {
    return columnData[0];
  } else {
    return columnData;
  }
}

function execListAction(action) {
  selection = getSelection();

  if (listFunctions[action]) {
    callback = listFunctions[action];
    return callback(selection);
  }
}

function expandVars(base, data) {
  while (varRegEx.test(base)) {
    match = varRegEx.exec(base);
    theVar = match[0];
    varLen = theVar.length;
    key = theVar.substr(1, varLen-2);
    value = eval('data.' + key);
    base = base.replace(theVar, value);
  }

  return base;
}

function removeAllListRows() {
  for (var i = 0; i < listOrder.length; i++) {
    var listKey = listOrder[i];
    var listRow = getListRowObjById(listKey);

    listRow.parentNode.removeChild(listRow);
  }
}

var preventSelection = new Function ("return false");

/*
 * Helpers to get event coordinates across IE and NS6
 */
function getEventX(event){
  if (event.pageX) return event.pageX;
  if (event.clientX){
    if (document.body.scrollLeft){
      return event.clientX + document.body.scrollLeft;
    } else {
      return event.clientX;
    }
  }
  return event.x;
}

function getEventY(event){
  if (event.pageY) return event.pageY;
  if (event.clientY){
    if (document.body.scrollTop){
      return event.clientY + document.body.scrollTop;
    } else {
      return event.clientY;
    }
  }
  return event.y;
}

/* Keypress Handler, so we can trap events like Ctrl+A */
function listKeyHandler(event) {
  if( jsPopupOpen ) {
    return;
  } 

  theEvent = event ? event : window.event;
  theKey = theEvent.which ? theEvent.which : theEvent.keyCode;

  control = theEvent.ctrlKey || theEvent.metaKey;
  shift   = theEvent.shiftKey;

  var isMac = navigator.platform.indexOf("Mac") > -1;
  if ((control) && 
      (theKey == 65 || theKey == 97)) {
    selectAll();
    return false;
  } else if (theKey == 38 || theKey == 40) {
    /* Do up */
    var selected = getListSelection();

    if (numSelected > 0) {
      if (selected.push) {
        len = (selected.length);
        var row = selectedRows[selected[len - 1]];
      } else {
        var row = selectedRows[selected];
      }
      
      if (theKey == 38) {
        newRow = row.previousSibling;
      } else if (theKey == 40) {
        newRow = row.nextSibling;
      }

      if (newRow && newRow.type != "header") {
        doSelect(newRow, theEvent);
      }
    }
  } else if (theKey == 46 || (theKey == 8 && isMac)) {
    /* Do delete if # of items is over zero and the focus isn't in a textbox */
    if (numSelected > 0 && !window.textboxFocussed) {
      if ( actionExistsAndAllowed( "DELETE" ) ) {
        /* the delete key is enabled and allowed, delete the item(s) */
        window.focus();
        execListAction( "DELETE" );
        return false;
      }
      else {
        /* the delete key is disabled or not allowed 
           - alert the user of the problem */
        msg = "I'm sorry, you do not have permission to delete these items.";
        alert ( msg );
        return;
      }
    }
  }
  return true;
}

function contentClickHandler(e) {
  /* Deselects all items if there's a click outside the table */
  e = e ? e : event;
  x = e.clientX;
  y = e.clientY;
  
  table = getTemplate('ListTable', false);
  if (!isInside(table, x, y)) {
    deselectAll();
  }
}

function ajaxDrawList(containerID, columnDefData, ajaxData, uKey, draggable, data, overFlow) {

  /* Reinitialize lists in case we're getting a redraw call. */
  listData = new Object();
  listOrder = new Array();
  listDraggable = draggable;

  listOrderedBy = data["orderBy"];
  for (var attr in data["orderLink"]) {
    listOrderByLinks[attr] = "javascript:doSort('" + data["orderLink"][attr] + "');";
  }

  //columnDefs = columnDefData;
  // columnDefData is an array and should be converted to an object.
  columnDefs = new Object();
  /*
  for ( cl in columnDefData) {
    rws = columnDefData[cl];
    if (!rws["title"]) {
      rws["title"] = "";
    }
    
    columnDefs[ rws["name"] ] = rws;
  }
  */
  for ( cl=0; cl < columnDefData.length; cl++) {
    rws = columnDefData[cl];
    if (!rws["title"]) {
      rws["title"] = "";
    }

    columnDefs[ rws["name"] ] = rws;
  }
  listKey = uKey;

  if (!ajaxData) {
    ajaxData = new Array();
  } else if (!ajaxData.push) {
    ajaxData = new Array( ajaxData );
  }

  for (i = 0; i < ajaxData.length; i++) {
    var uid = ajaxData[i][listKey];
    listOrder.push(uid);
    listData[uid] = ajaxData[i]
  }

  var listContainer = document.getElementById(containerID);

  var headerDiv = document.getElementById("ListHeaderDiv");

  if ( !headerDiv ) {
    headerDiv = document.createElement("div");
    headerDiv.id = "ListHeaderDiv";
    listContainer.appendChild(headerDiv);
  }  

  var listDiv = document.getElementById("ListDiv");

  if (!listDiv) {
    listDiv = document.createElement("div");
    listDiv.id = "ListDiv";
    listDiv.style.width = "100%";
    listDiv.style.overflow = "auto";
    listContainer.appendChild(listDiv);
  }

  listShow("ListDiv");

  if (listFunctions["PAGINATE"]) {
    var prow = document.getElementById("ListPagination");
    if (!prow) {
      prow = getTemplate( "ListPaginationTemplate", true);
      prow.id = "ListPagination";
      prow.style.display = "block";
      headerDiv.appendChild(prow);
    }
    updatePaginationDisplay ( data );
  }    


  var headerTable = document.createElement("table");
  var oldHeader = document.getElementById("ListHead");
  
  var currentHeader = document.getElementById("CurrentHeader");
  if(currentHeader) {
    currentHeader.parentNode.removeChild(currentHeader);  
  }

  var newHeader = oldHeader.cloneNode(true);
  newHeader.id = "CurrentHeader";

  if (ie) {
    newHeader.style.display = "block";
  } else {
    newHeader.style.display = "table-row-group";
  }

  newHeader.firstChild.style.width = "100%";

  var tr1;
  if( !overFlow ) {
    nd = listDiv.firstChild.childNodes
    tr1 = nd[nd.length - 1].firstChild;

    if (tr1) {
      for (var i = 0; i < oldHeader.firstChild.childNodes.length; i++) {
       oh = oldHeader.firstChild.childNodes[i];
       nh = newHeader.firstChild.childNodes[i];
       nh.style.width = oh.offsetWidth -1;
       tr1.childNodes[i].style.width = oh.offsetWidth ;
       var newImg = document.createElement("img");

       newImg.src = imagesURL + "iconset/pixel.gif";
       newImg.width = oh.offsetWidth - 10;
       newImg.height = 1;
       nh.appendChild(newImg);
       // use a div to make sure it goes to new line
       var div = document.createElement("div");
       newImg2 = newImg.cloneNode(true);
       div.appendChild(newImg2);
       tr1.childNodes[i].appendChild(div);
       tr1.childNodes[i].style.width = oh.offsetWidth - 10;
      }
    }
  }
  // as a new header is added so the old one should be hidden now. 
  // more than one header will cause extra rows(empty rows)in list page.
  var veryOldHeader = document.getElementById("OldHeader");
  if( veryOldHeader) {
    veryOldHeader.parentNode.removeChild(veryOldHeader);  
  } 
  oldHeader.id = "OldHeader";
  oldHeader.style.display = "none";  



  headerTable.style.width = "100%";
  headerTable.appendChild(newHeader);
  headerDiv.appendChild(headerTable);

  listDiv.style.height = (listContainer.offsetHeight - headerDiv.offsetHeight) + "px";


  var headerRow = newHeader.firstChild;

  if ( ie &&  overFlow ) {
    // For some reason IE messes up the padding of the header row when it
    // gets moved from one table or another, so we have to set the padding
    // for all cells to 0.
    for (var i = 0; i < headerRow.childNodes.length; i++) {
      var theHeader = headerRow.childNodes[i];
      theHeader.style.padding = "0px";
    }
  }

  if ( tr1 ) {
    //make the last column 100% so they line up
    tr1.childNodes[tr1.childNodes.length - 1].style.width = "100%";
    headerRow.childNodes[headerRow.childNodes.length - 1].style.width  = "100%";
  } else {
    addEmptyCell();
  }  
}

function addEmptyCell() {
  // This function adds an empty square cell to the list if there is a
  // scrollbar, and removes it if there isn't.

  var listDiv = document.getElementById("ListDiv");
  var listHead = document.getElementById("CurrentHeader");
  var hasEmpty = document.getElementById("ListEmptyCell");

  if (listDiv && listHead) {
    if (listDiv.scrollHeight > listDiv.offsetHeight) {
      if (!hasEmpty) {
        var headerRow = listHead.firstChild;
        var emptyCell = headerTemplate.cloneNode(true);

        emptyCell.id = "ListEmptyCell";
        emptyCell.innerHTML = "";
        emptyCell.style.width = "5px";
        headerRow.appendChild(emptyCell);
      }
    } else if (hasEmpty) {
      hasEmpty.parentNode.removeChild(hasEmpty);
    }
  }
}

function updatePaginationDisplay ( data ) {
  var prow = document.getElementById("ListPagination");
    if( data ) {
      prow.style.display = "block";
      var newFirst = document.getElementById("NewFirst");    
      var newPrev = document.getElementById("NewPrev");    
      var newSpan = document.getElementById("NewSpan");
      var newNext = document.getElementById("NewNext");
      var newLast = document.getElementById("NewLast");    
      var totalSpan = document.getElementById("TotalListItems");

      if (data["prevLink"]) {
        newFirst.url = data["firstLink"];
        newFirst.style.display = "inline";
        newFirst.style.marginRight = "3px";
        newPrev.url = data["prevLink"];
        newPrev.style.display = "inline";
      } else {
        newPrev.style.display = "none";
        newFirst.style.display = "none";
      }
  
      if (data["nextLink"]) {
        newNext.url = data["nextLink"];
        newNext.style.display = "inline";
        newLast.url = data["lastLink"];
        newLast.style.display = "inline";
        newLast.style.marginLeft = "3px";
      } else {
        newNext.style.display = "none";
        newLast.style.display = "none";  
      }

      // webmail is passing messageTotal, others totalItems
      var totalItems = data["messageTotal"] || data["totalItems"];
      
      var currPage = Math.floor((Number(data["start"])+1)/data["maxPerList"]) + 1;
      var lastPage = totalItems/data["maxPerList"];
      if ( Math.floor(lastPage) != lastPage ) {
        var lastPage = Math.floor(lastPage) + 1;
      } 
      if (lastPage == 0) {
        lastPage = 1;
      } 
      newSpan.innerHTML = "Page " + currPage + " of " + lastPage;
      if(totalItems) {
        totalSpan.innerHTML = "(Total: " + totalItems + ")";
      } else {
        totalSpan.innerHTML = "";
      }
    }
}

function updateTotalListItems( num ) {
  var totalSpan = document.getElementById("TotalListItems");
  var txt = totalSpan.innerHTML;
  if (txt) {
    var currentNum = Number((txt.split(":")[1]).split(")")[0]);
    var newNum = currentNum - num;
    if ( newNum < 0 ) newNum = 0;
    totalSpan.innerHTML = "(Total: " + newNum + ")";
  }
}

function doPagination(event) {
  event = event || window.event;
  var button = this;

  if ( event.currentTarget ) {
    button = event.currentTarget;
  } else if ( event.srcElement ) {
    button = event.srcElement;
  }

  paginationFunc = listFunctions["PAGINATE"];
  if (paginationFunc) {
    paginationFunc(button.url, button.value);
  }
}

function generalPaginate(url, mPP, altUrl, extraArgs) {
  if (!url) {
    maxPerList = mPP;
    url = altUrl + "?";
    pageStart = 0;
  } else {
    url += "&";
  }  
  args = getArgs();
  url += args;
  if (extraArgs) {
    url += extraArgs;
  }
  showProgressBar();
  makeAJAXCall(xmlHeaders, url, true, "xmlHeaders");
}
function getArgs() {
  queryStr = searchOptions.getQueryString();
  if ( order ) {
   queryStr += "&order=" + order;
  }

  if ( orderBy ) {
   queryStr += "&orderBy=" + orderBy;
  }

  if ( maxPerList ) {
   queryStr += "&maxPerList=" + maxPerList;
  }
  if (pageStart) {
    //queryStr += "&start=" + pageStart;
  }
  return queryStr;
}

function generalProcessHeaders(data, listName, listId) {
  if (data["error"]) {
    hideProgressBar();
    alert(data["error"]);
    return;
  }
  clearList("HeaderList");
  ajaxDrawList("HeaderList", data["columns"], data[listName], listId, false, data);
  if (data["orderBy"]) {
    orderBy = data["orderBy"];
  }
  if (data["order"]) {
    order = data["order"];
  }
  // start can be undefine or 0 or a number
  pageStart = Number(data["start"]);
 
  if (data["maxPerList"]) {
    maxPerList = data["maxPerList"];
  }
  if (firstLoad && maxPerList) {
    setMaxPerList(maxPerList);
  }
  firstLoad = false;
  headersLoaded = true;
  hideProgressBar();
  resizeHeaderList("ExtraHeader");
}

function showProgressBar( message ) {
  var prDisplay = document.getElementById( "ProgressBarDisplay" );
  if (message) {
    prDisplay.innerHTML = message + "...";
  } else {
    prDisplay.innerHTML = "Processing...";      
  }
  var scContent = document.getElementById( "ScrollableContent" );
  var prContain    = document.getElementById( "ProgressBarContainer" );
  prContain.style.top = scContent.offsetHeight - prContain.offsetHeight;
  prContain.style.visibility = "visible";
} 

function showProgressBarIfNotLoaded() {
  if (firstLoad) {
    showProgressBar("Loading");
  }
}

function hideProgressBar() {
  var prContain    = document.getElementById( "ProgressBarContainer" );
  prContain.style.visibility = "hidden"; 
}

function doSort(url) {
  showProgressBar();
  makeAJAXCall(xmlHeaders, url, true, "xmlHeaders");
}

function ajaxAddListRows( ajaxData, key, pos ) {
  var container = document.getElementById("HeaderList");
  var newRow = rowTemplate.cloneNode(true);
  listData[ ajaxData[key] ] = ajaxData;
  listOrder.push(key);
  addListRow(container, newRow, ajaxData, false, pos);
  hideNoContent();
  doCallbacks();
}

/*
 * This function is for updating text columns only.
 * This should be updated to work with links, html, images... 
 */
function ajaxUpdateListRows ( key, column, val ) {
  var listRow = getListRowObjById( key );
  pos = getColumnDefsPos( column );

  if (pos == null) {
    alert( "Invalid column name");
    return;
  }
  cell = listRow.childNodes[pos];
  if (cell.firstChild) {
    cell.removeChild(cell.firstChild);
  }  

  textNode = document.createTextNode(val);
  cell.insertBefore(textNode, cell.firstChild);
  listData[key][column] = val;
}


function ajaxUpdateAllListRows(rowData) {
  var key = rowData[listKey];
  var listRow = getListRowObjById( key );
  if (!listRow)  return;

  var row = 0;
  for ( cl in columnDefs) {
    var clNodes = listRow.childNodes[cl];
    // listRow is different when call by ajax
    if (!clNodes) {
      var clNodes = listRow.childNodes[row];
    }  
    var clName = columnDefs[cl]["name"];
    var displayText = getDisplayText(columnDefs[cl], rowData);
    var columnText = eval('rowData.' + clName);

    if (clNodes && clNodes.firstChild) {
      if(clNodes.firstChild.firstChild && clNodes.firstChild.firstChild.nodeName == "IMG") {
        if(clNodes.childNodes[1]) {
          clNodes.removeChild(clNodes.childNodes[1]);
        }
      } else {
        clNodes.removeChild(clNodes.firstChild);
      }
    }
    if (columnDefs[cl].bgColor) {
      var bgColor = eval("rowData." + columnDefs[cl].bgColor);
    } else {
      var bgColor = "";
    }

    if (columnDefs[cl].textColor) {
      var textColor = eval("rowData." + columnDefs[cl].textColor);
    } else {
      var textColor = "";
    }

    if(clNodes) {
      addCells(clNodes, columnDefs[cl], displayText, columnText, bgColor, textColor );
    }
    row += 1;
  }
  listData[key] = rowData;
}
// This function is called when page resizes ( when using Ajax list)
function resizeListFrame() {
  resizeHeaderList("ExtraHeader", true);
}

function resizeHeaderList(extraDivName, browserResize, aditionalHeight) {
  var headerList = document.getElementById("HeaderList");
  var ft = document.getElementById("FixedTop");
  var listDiv = document.getElementById("ListDiv");
  var listPagination = document.getElementById("ListPagination");
  var folderTree = document.getElementById("FolderTree");
  var fixBottom  = document.getElementById( "FixedBottom" );

  if (folderTree) {
    var ss_folderWidth = folderTree.offsetWidth;
  } else {
    var ss_folderWidth = 0;
  }
  
  extraHeight = 0;
  if (!aditionalHeight){
    aditionalHeight = 0;
  }
  if ( extraDivName ) {
    var extraDiv = document.getElementById(extraDivName);
    if(extraDiv) {
      extraHeight = extraDiv.offsetHeight ;
    }
  }
  if ( document.all ) {
    availableHeight = document.body.offsetHeight - ft.offsetHeight - extraHeight - fixBottom.offsetHeight - 1;
    availableWidth = document.body.offsetWidth - ss_folderWidth;      
  } else {
    availableHeight = window.innerHeight - ft.offsetHeight - fixBottom.offsetHeight - extraHeight - 3;
    availableWidth = window.innerWidth - ss_folderWidth;
  }

  var oldHeader = document.getElementById("OldHeader");
  var currentHeader = document.getElementById("CurrentHeader");
  var headerDiv = document.getElementById("ListHeaderDiv");
  
  if (oldHeader && currentHeader && browserResize) {
    var headerTable = document.createElement("table");
    if (ie) {
      oldHeader.style.display = "block";
    } else {
      oldHeader.style.display = "table-row-group";
    }

    currentHeader.parentNode.removeChild(currentHeader);
    var listDiv = document.getElementById("ListDiv");
    nd = listDiv.firstChild.childNodes
    tr1 = nd[nd.length - 1].firstChild;

    if (tr1) {
      for (var i = tr1.childNodes.length - 1; i >= 0; i--) {
        oh = oldHeader.firstChild.childNodes[i];
        var thisImg = tr1.childNodes[i].childNodes[tr1.childNodes[i].childNodes.length-1];
        if (thisImg) {
          thisImg.parentNode.removeChild(thisImg);
        }
        tr1.childNodes[i].style.width = null;
      }
     
    }
    
  }
  headerList.parentNode.style.overflow = "hidden";
  headerList.style.height = availableHeight  + aditionalHeight ;
  headerList.style.width = availableWidth;
  if (listDiv) {
    listDiv.style.height = (headerList.offsetHeight - headerDiv.offsetHeight  + aditionalHeight ) + "px";
    listDiv.style.width = availableWidth;
    listDiv.style.overflowX = "hidden";
  }
}

function getColumnDefsPos( column ) {
  pos = 0;
  for ( cl in columnDefs) {
    if ( cl == column ) {
      return pos;
    }
    pos += 1;
  }
  return null;
}


function getColumnDefsPosByName( columnName ) {
  var pos = 0;
  for ( cl in columnDefs) {
    if ( columnDefs[cl]["name"] == columnName ) {
      return pos;
    }
    pos += 1;
  }
  return null;
}

function getIdxById( key ) {
  var listRow = getListRowObjById( key );
  return listRow.idx;
}

function clearList(containerID) {
  deselectAll();
  var container = document.getElementById(containerID);
  var listNoContent = document.getElementById("ListNoContent");

  listNoContent.style.visibility = "hidden";

  if (container.firstChild) {
    /* This should be the table... */
    var listTable = container.firstChild;

    if (listTable.firstChild) {
      /* We need to delete the body of the table. */
      var listHeader = document.getElementById("ListHead");
      var listBody = document.getElementById("ListBody");

      while (listTable.firstChild && listTable.firstChild.nodeName == "THEAD") {
        listTable.removeChild(listTable.firstChild);
      }

      if (listBody) {
        listBody.parentNode.removeChild(listBody); /* Delete the body */
      }

      while (listTable.firstChild && listTable.firstChild.nodeName == "TBODY") {
        listTable.removeChild(listTable.firstChild);
      }
    }
  }
}

function startListDrag(event) {
  event = event || window.event;
  if (event.ctrlKey != undefined) {
    var control = event.ctrlKey || event.metaKey;
  } else {
    var control = (event.modifiers & Event.CONTROL_MASK);
  }

  var row = this || window.event.srcElement;
  listDragging = 1;
  listDraggingContinued = 0;

  var ft = document.getElementById("FixedTop");
  ss_attachEvent(ft, "selectstart", preventSelection);

  var w = getTopWindow();

  try {
    var fs = w.document.getElementById("mainSet"); // The main frame
    if (fs) {
      ss_attachEvent(fs, "selectstart", preventSelection);
      ss_attachEvent(fs, "drag", preventSelection);
    }
  } catch(e) {
    // Ignore.  Once again, if our parent window is at a different URL you get
    // a security exception here which we can safely ignore.
  }

  var dragObj = document.getElementById("Draggable");
  while (dragObj.firstChild) {
    dragObj.removeChild(dragObj.firstChild);
  }

  if (!selectedRows[row.key] && !control) {
    deselectAll();
    selectRow(row);
  }

  if (numSelected == 1) {
    dragObj.innerHTML = this.firstChild.innerHTML;
    if (listFunctions['DRAG_COLUMN']) {
      var clPos = getColumnDefsPos( listFunctions['DRAG_COLUMN'] );
      if (clPos) {
        dragObj.innerHTML = this.childNodes[clPos].innerHTML;
      }  
    }  
  } else {
    dragObj.innerHTML = 'Dragging <span class="Warning">' + numSelected + '</span> items.';
  }

  addClassModifier(dragObj, "TransHeavy");
  return false;
}


function stopListDrag(event) {
  var ft = document.getElementById("FixedTop");
  var w = getTopWindow();

  try {
    var fs = w.document.getElementById("mainSet"); // The main frame
  } catch(e) {
    var fs = false;
  }

  event = event || window.event;

  try {
    if (listDragging || treeDragging) {
      dropOnTree(event);
    }
    dragObj = document.getElementById("Draggable");
    dragObj.style.display = "none";

    listDragging = 0;
    listDraggingContinued = 0;
  } catch(e) {
    dragObj = document.getElementById("Draggable");
    dragObj.style.display = "none";

    listDragging = 0;
    listDraggingContinued = 0;
  }
  try {
    ss_detachEvent(ft, "selectstart", preventSelection);
    if (fs) {
     ss_detachEvent(fs, "selectstart", preventSelection);
     ss_detachEvent(fs, "drag", preventSelection);
    }

    ss_detachEvent(dragObj, "mousedown", startListDrag);
    ss_detachEvent(dragObj, "mouseup", stopListDrag);
  } catch(e) {
    alert(e.message || e.description);
  }
}

function doListDrag(event) {
  if (window.event && window.event.srcElement) {
    event = window.event;
  }
  if (!listDragging) return true;
  listDraggingContinued = 1;

  var ft = document.getElementById("FixedTop");
  var ftHeight = ft.offsetHeight;

  var folderList = document.getElementById("FolderTree");

  var x = getEventX(event);
  var y = getEventY(event) - ftHeight;

  clearTimeout(openTimeout);
  showDraggableRow(event);

  
  if ((x < folderList.offsetWidth) && (folderList.offsetHeight - y <= 10) && (folderList.offsetHeight < folderList.scrollHeight)) {
    if (!scrollingFolders) {
      scrollingFolders = true;
      scrollInterval = setInterval( function() { folderList.scrollTop += 10 }, 50);
      //folderList.scrollTop += 10;
    }
  } else if ((x < folderList.offsetWidth) && (y <= 10) && (folderList.scrollTop > 0)) {
    if (!scrollingFolders) {
      scrollingFolders = true;
      scrollInterval = setInterval( function() { folderList.scrollTop -= 10 }, 50);
      //folderList.scrollTop -= 10;
    }
  } else {
    if (scrollingFolders) {
      clearTimeout(scrollInterval);
    }
    scrollingFolders = false;
  }

  return false;
}

function showDraggableRow(event) {
  var dragObject = document.getElementById("Draggable");
  var folderTree = document.getElementById("FolderTree");
  var ft = document.getElementById("FixedTop");
  var ftHeight = ft.offsetHeight;

  var x = getEventX(event);
  var y = getEventY(event) - ftHeight - dragHeightOffset;

  dragObject.style.display = "inline";
  dragObject.style.left = x + 5;
  dragObject.style.top = y + 5;
 
  if (x < folderTree.offsetWidth) {

    if (ie) {
      var folderRow = getRowUnderCursor(event)

      if (folderRow) {
        if (defaultTree) {
          openTimeout = setTimeout(defaultTree + ".openTreeFolder('" + folderRow.rowId + "', true, true)", 1000);
        } else {
          openTimeout = setTimeout("openTreeFolder('" + folderRow.rowId + "', true, true)", 1000);
        }
      }
    } else {
    for (var i = 0; i < treeDroppables.length; i++) {
        var folderRow = treeDroppables[i];
        if (((folderRow.offsetTop - folderTree.scrollTop)) < y && y < ((folderRow.offsetTop + folderRow.offsetHeight - folderTree.scrollTop)) && (folderRow.offsetLeft < x && x < (folderRow.offsetLeft + folderRow.offsetWidth))) {
          addClassModifier(folderRow.childNodes[1].childNodes[1], "OverBg");
          openTimeout = setTimeout("openTreeFolder('" + folderRow.rowId + "', true, true)", 1000);
          if (defaultTree) {
            openTimeout = setTimeout(defaultTree + ".openTreeFolder('" + folderRow.rowId + "', true, true)", 1000);
          } else {
            openTimeout = setTimeout("openTreeFolder('" + folderRow.rowId + "', true, true)", 1000);
          }
          //openTreeFolder(folderRow.rowId, true, true);
        } else {
          removeClassModifier(folderRow.childNodes[1].childNodes[1], "OverBg");
        }
      }
    }
  }
}

function updateRowColors() {
  var lb = document.getElementById("ListBody");
  var selected = getListSelection();

  if (!selected.length) {
    selected = new Array(selected);
  }

  for (var i = 0; i < lb.childNodes.length; i++) {
    var theRow = lb.childNodes[i];
    theRow.idx = i;
    
    if (i % 2) {
      if (!selectedRows[theRow.key]) {
        addClassModifier(theRow, "AltBg");
      }
    } else {
      removeClassModifier(theRow, "AltBg");
    }
  }
}

function showNoContent() {
  var listNoContent = document.getElementById("ListNoContent");
  listNoContent.style.visibility = "visible";
}

function hideNoContent() {
  var listNoContent = document.getElementById("ListNoContent");
  listNoContent.style.visibility = "hidden";
}

function getTopWindow() {
  var w = window;

  while (w != w.parent) {
    w = w.parent;
  }

  return w
}

function isAjaxWorking() {
  try {
    // just a test to see if ajax is working or not
    var test = AJAXRequest(test);
    test.open("get", "test", true); // this gives error in some browsers.
    return true;
  } catch(e) { 
    return false;
  }        
}


/*
 * popup window functions
 */
function setPopupAlignment(popupObj, popupAlign) {
  var objHeight = popupObj.offsetHeight;
  var objWidth = popupObj.offsetWidth;

  if (ie) {
    bodyWidth = document.body.offsetWidth;
    bodyHeight = document.body.offsetHeight;
  } else {
    bodyWidth = window.innerWidth;
    bodyHeight = window.innerHeight;
  }

  var valign = "M";
  var halign = "C"; 

  if ( popupAlign )  {
    valign = (popupAlign.substr(0, 1)).toUpperCase();
    if ( popupAlign.substr(1, 1) ) {  
      halign = (popupAlign.substr(1, 1)).toUpperCase();
    }  
  }

  switch (valign) {
    case "T": popupObj.style.top = 0; break;
    case "B": popupObj.style.top = bodyHeight - objHeight; break;
    case "M": popupObj.style.top = (bodyHeight / 2) - (objHeight / 2); break;
  }
  switch (halign) {
    case "L": popupObj.style.left = 0; break;
    case "R": popupObj.style.left = bodyWidth - objWidth;  break;
    case "C": popupObj.style.left = ((bodyWidth / 2) - (objWidth / 2)); break;
  }
  
  if (popupWindows[popupObj.id]) {
    thisPop = popupWindows[popupObj.id];
  } else {
    thisPop = new Object();
    popupWindows[popupObj.id] = thisPop;
  }
  thisPop["aligned"] = 1;
  thisPop["height"] = popupObj.offsetHeight;
  thisPop["width"] = popupObj.offsetWidth;
  thisPop["top"]  = removePX( popupObj.style.top );
  thisPop["left"] = removePX( popupObj.style.left);
}

function fulSizePopup(imgObj, popupId) {
  if( imgObj.src.indexOf("ss_expand2_popup.png") == -1 ) {
    imgObj.src = imagesURL + "/iconset/ss_expand2_popup.png";
    imgObj.title = "Restore Down";
    if (ie) {
      popupWidth = document.body.offsetWidth - 14;
      popupHeight = document.body.offsetHeight -4;
    } else {
      popupWidth = window.innerWidth - 31;
      popupHeight = window.innerHeight;
    }
    resizePopup(popupId, popupWidth, popupHeight, 0, 0);
  } else {
    imgObj.src = imagesURL + "/iconset/ss_expand_popup.png";
    imgObj.title = "Maximize";
    thisPop = popupWindows[popupId];
    popupWidth = thisPop["width"];
    popupHeight = thisPop["height"];
    popupTop = thisPop["top"];
    popupLeft = thisPop["left"];
    resizePopup(popupId, popupWidth, popupHeight, popupTop, popupLeft);
  }
}

function resizePopup(popupId, popupWidth, popupHeight, popupTop, popupLeft) {
    var popTitle = popupId + "Title";
    var popMainDiv = popupId + "MainDiv";
    var scrollId = popupId + "ScrollableContent";
    var fixId    = popupId + "FixContent";
    var butId    = popupId + "Buttons";
    var bottomFixId = popupId + "FixBottomContent";

    var popupObj = document.getElementById(popupId);
    var mainDivObj = document.getElementById(popMainDiv);
    
    var titleObj = document.getElementById(popTitle);
    var scrollObj = document.getElementById(scrollId);
    var fixObj = document.getElementById(fixId);
    var butObj = document.getElementById(butId);
    var fixBottomObj = document.getElementById(bottomFixId);

    if (! (butObj && titleObj) ) return;

    if ( ie ) {
      availableHeight = document.body.offsetHeight - 30;
    } else {
      availableHeight = window.innerHeight - 40;
    }
    addZindex( popupObj );

    if (popupWidth <150) {
      popupWidth = 150;
    }

    if(fixObj) {
      if(ie) {
        fixObj.style.width = popupWidth ;
      }
      fixObjH = fixObj.offsetHeight;
    } else {
      fixObjH = 0;
    }

    if(fixBottomObj) {
      if(ie) {
        fixBottomObj.style.width = popupWidth ;
      }
      fixBottomObjH = fixBottomObj.offsetHeight;
    } else {
      fixBottomObjH = 0;
    }
    
    minH =  titleObj.offsetHeight + butObj.offsetHeight + fixObjH + fixBottomObjH + 5;

    if (popupHeight > availableHeight) {
      popupHeight = availableHeight;
    }

    if(popupHeight < minH) {
      popupHeight = minH;
    }
    if (ie) {
      popupObj.style.width = popupWidth + 27;
      mainDivObj.style.width = popupWidth - 14;
      popupObj.style.height = popupHeight + 44;
      popupObj.firstChild.style.height = popupHeight + 44;
      mainDivObj.style.height = popupHeight - 7;
    } else {
      popupObj.style.width = popupWidth + 27;
      mainDivObj.style.width = popupWidth - 3;
      popupObj.style.height = popupHeight + 40;
      popupObj.firstChild.style.height = popupHeight + 40;
      mainDivObj.style.height = popupHeight;
    }

    scrollW = popupWidth;
    scrollH = popupHeight - titleObj.offsetHeight - butObj.offsetHeight - fixObjH  - fixBottomObjH;

    if (ie) { 
      scrollW -= 14;
      scrollH -= 8;
    }

    titleObj.style.width = scrollW;    
    scrollObj.style.width = scrollW;
    scrollObj.style.height = scrollH;
    scrollObj.firstChild.style.height = scrollH ;

    if(popupTop || popupTop == 0) {
      popupObj.style.top = popupTop;
    }
    if (popupLeft || popupTop == 0 ) {
      popupObj.style.left = popupLeft;
    }
    popupTop = removePX(popupObj.style.top);
    if( popupTop < 1 ) {
      popupObj.style.top = 1;
    }
}

function isPopupOpen(popupId) {
  var popupObj = document.getElementById(popupId);
  if (popupObj && popupObj.style.display == "block") {
    return true;
  } else {
    return false;
  }
}

function addZindex( popupObj, popupId ) {
  if ( !popupObj ) {
    popupObj = document.getElementById(popupId);
  }
  if (popupObj) {
    popupObj.style.zIndex =  ++popupHighZindex;
  }  
}

function doSimpleResize(event) {
  try {
    if (resizingPopupWindow) {
      var popupObj = document.getElementById(resizingPopupWindow);
      var popupContainer = popupObj.parentNode.parentNode.parentNode.parentNode.parentNode;
      var ft = document.getElementById("FixedTop");
      var sc = document.getElementById("ScrollableContent");
      var pos = mouseCoords(event);

      var optionsObj = dragOptions[popupObj.id];
      if (optionsObj) {
        if (optionsObj.useGrid) {
          dragStep = gridSize;
          halfStep = gridSize / 2;
        } else {
          dragStep = 1;
          halfStep = 1;
        }
      }

      var newHeight = pos.y - popupOuterDiv.offsetTop - ft.offsetHeight + sc.scrollTop;
      var newWidth  = pos.x - popupOuterDiv.offsetLeft + sc.scrollLeft;

      yDelta = newHeight % dragStep;
      if (yDelta == 0) {
        popupObj.style.height = newHeight;
      } else if (yDelta <= halfStep) {
        popupObj.style.height = newHeight - yDelta;
      } else {
        popupObj.style.height = newHeight + (dragStep - yDelta);
      }

      xDelta = newWidth % dragStep;
      if (xDelta == 0) {
        popupObj.style.width = newWidth;
        if (ie) { popupContainer.style.width = newWidth + 30; }
      } else if (xDelta <= halfStep) {
        popupObj.style.width = newWidth - xDelta;
        if (ie) { popupContainer.style.width = newWidth - xDelta + 30; }
      } else {
        popupObj.style.width = newWidth + (dragStep - xDelta);
        
        if (ie) { popupContainer.style.width = newWidth + (dragStep - xDelta) + 30 }
      }

      addDraggableCoords(popupObj, true);
      thisPop = popupWindows[resizingPopupWindow];
      if(thisPop) {
        thisPop["height"] = newHeight;
        thisPop["width"] = newWidth;
      }
    }

  } catch(e) {
    resizingPopupWindow = false;
  }
}

function startResizingPopup( event, popupId, useSimple ) {
  event = event || window.event;
  
  event.cancelBubble = true;
  event.returnValue = false;
  if (event.stopPropagation) { event.stopPropagation() }; 
  if (event.preventDefault) { event.preventDefault() };

  /*var optionsObj = dragOptions[popupId];
  if (optionsObj) {
    if (optionsObj.useGrid) {
      dragStep = gridSize;
      halfStep = gridSize / 2;
    } else {
      dragStep = 1;
      halfStep = 1;
    }
  }*/

  for (var i = 0; i < startDragCallbacks.length; i++) {
    startDragCallbacks[i]();
  }

  var expandImg = document.getElementById(popupId + "ExpandImg");
  if (expandImg && expandImg.src.indexOf("ss_expand2_popup.png") != -1 ) {
    return;
  }

  resizingPopupWindow = popupId;
  if (useSimple) {
    // This is a hack for the dashboard for now.  Make this more portable later.
    var popupObj = document.getElementById(popupId);
    popupOuterDiv = popupObj.parentNode.parentNode.parentNode.parentNode.parentNode;
    if (popupOuterDiv.className != "SS_Widget") {
      popupOuterDiv = popupObj.parentNode.parentNode;
    }
    // End hack.

    ss_attachEvent(document, "mousemove", doSimpleResize);
  } else {
    ss_attachEvent(document, "mousemove", doPopupBasicDrag);
  }
  ss_attachEvent(document, "mouseup", stopResizingPopup);

  ss_attachEvent(document, "selectstart", preventSelection);
  ss_attachEvent(document, "drag", preventSelection);
  ss_attachEvent(document, "mousedown", preventSelection);
}

function stopResizingPopup(popupId) {
  document.onmousemove = null;

  for (var i = 0; i < stopDragCallbacks.length; i++) {
    stopDragCallbacks[i]();
  }

  ss_detachEvent(document, "selectstart", preventSelection);
  ss_detachEvent(document, "drag", preventSelection);
  ss_detachEvent(document, "mousedown", preventSelection);
  ss_detachEvent(document, "mousemove", doSimpleResize);
  ss_detachEvent(document, "mousemove", doPopupBasicDrag);

  resizingPopupWindow = false;
}

function adjustJSPopup(popName, extraHeight) {
  if (!extraHeight) {
    extraHeight = 0;
  }
  var popupObj = document.getElementById(popName);
  var newHeight = popupObj.offsetHeight;
  var newWidth = popupObj.offsetWidth;
  if (ie) {
    newHeight -= 44 + extraHeight;
    newWidth -= 27;
  } else {
    newHeight -= 51 + extraHeight;
    newWidth -= 38;
  }
  
  var titleObj = document.getElementById(popName + "Title");
  var closeIcon = document.getElementById(popName + "CloseIcon");
  var stretchIcon = document.getElementById(popName + "StretchIcon");
  if (titleObj) {
    // in ie some times stretch icon is not moved to proper place so resizing twice
    // will fix this problem
    resizePopup(popName, newWidth-1, newHeight-1);
    resizePopup(popName, newWidth, newHeight);
  }
  if(!ie) {
    if (closeIcon) {
      closeIcon.style.top = 30;
      closeIcon.style.right = 25;
    }
    if (stretchIcon) {
      stretchIcon.style.bottom = 17;
      stretchIcon.style.right = 16;
    }
  }
}


function doPopupBasicDrag(event) {
  try {
    if (resizingPopupWindow) {
      var popupObj = document.getElementById(resizingPopupWindow);
      var pos = mouseCoords(event);

      //var newHeight = pos.y - removePX(popupObj.style.top);
      //var newWidth  = pos.x - removePX(popupObj.style.left);
      var newHeight = pos.y - popupObj.offsetTop;
      var newWidth  = pos.x - popupObj.offsetLeft;
      resizePopup(resizingPopupWindow, newWidth, newHeight);

      thisPop = popupWindows[resizingPopupWindow];
      if(thisPop) {
        thisPop["height"] = newHeight;
        thisPop["width"] = newWidth;
      }
      popupResizeExtraAction(resizingPopupWindow, newWidth, newHeight);
    }

  } catch(e) {
    resizingPopupWindow = false;
  }
}

/*
 * this function can be overwritten if necessary
*/
function popupResizeExtraAction(poupId, newWidth, newHeight) {}

function removePX( val ) {
  return val.substr(0, (val.length-2) );
}

function getButtonClone( butName ) {
  var oldButton = document.getElementById(butName + "_BUTTON");
  if (!oldButton) {
    return false;
  }
  var newButton = oldButton.cloneNode(true);
  newCode = butName + "_CLONE";

  oldAction = menuRegistry.getAction(butName);
  
  newAction = new Object();
  for ( key in oldAction ) {
    newAction[key] = oldAction[key];
  }
  newAction.code = newCode;
  newButton.menuAction = newCode;

  ss_attachEvent(newButton, "mouseover", addBorder);
  ss_attachEvent(newButton, "mouseout", removeBorder);

  menuRegistry.addMenu(newCode, "");
  toolbarRegistry.addButton(newAction);
  menuCode = menuRegistry.actionMenus[butName];

  menu = menuRegistry.getMenu(menuCode);

  menuRegistry.actionMenus[newCode] = menuRegistry.actionMenus[butName];
  menu.actions[newCode] = newAction;
  menu.actionLimits[ALWAYS].push(newCode);

  newAction.toolButton = newButton;
  newAction.enableLimit = ALWAYS;
  enableMenuAction( newAction );

  return newButton;
}  

function setPopupTitle(popupId, popTitle) {
  var titleObj = document.getElementById(popupId + "Title");
  if(titleObj) {
   titleObj.innerHTML = popTitle
  }
}

function setPopupFixDiv(popupId, fixContent) {
  var scollObj = document.getElementById( popupId + "ScrollableContent" );  
  var fixObj = document.getElementById( popupId + "FixContent" ); 
  if (fixObj) {
    fixObj.parentNode.removeChild(fixObj);
  }
  fixContent.id = popupId + "FixContent";
  scollObj.parentNode.insertBefore(fixContent, scollObj);  
}

function setPopupScrollDiv(popupId, scrollContent) {
  var scollObj = document.getElementById( popupId + "ScrollableContent" ); 
  while (scollObj.firstChild) {
    scollObj.removeChild(scollObj.firstChild);
  }  
  scollObj.appendChild(scrollContent);
}

function text2html( textarea ) {
  // this is a very simple implementation, it probably needs more work
  content = textarea.value;
  content = content.replace( /[<]/g, "&lt;" );
  content = content.replace( /[>]/g, "&gt;" );
  content = content.replace( /\r\n|\n/g, "<br />" );
  textarea.value = content;
  converted = true;
}

function getWindowHeight() {
  if (ie) {
    return document.body.offsetHeight;
  } else {
    return window.innerHeight;
  }

}

function getWindowWidth() {
  if (ie) {
    return document.body.offsetWidth;
  } else {
    return window.innerWidth;
  }
}

function getNameEmailFormat(email, name) {
  if ( email == name ) {
    result = email
  } else {
    result = '"' + name + '" <' + email + '>';
  }
  return result
}

/*
 * Remove spaces from beginning and end of a string.
 */
function stripString( str ) {
  while ( str.substr((str.length -1), 1) == " " || str.substr(0,1) == " ") {
    if (str.substr((str.length -1), 1) == " ") {
      str = str.substr(0, (str.length -1) );
    }  
    if (str.substr(0, 1) == " ") {
      str = str.substr(1);
    } 
  }  
  return str;
}

/*
cbb function by Roger Johansson, http://www.456bereastreet.com/

For adding rounded corners.
*/
var cbb = {
  init : function() {
    // Check that the browser supports the DOM methods used
    if (!document.getElementById || !document.createElement || !document.appendChild) return false;
    var oElement, oOuter, oI1, oI2, tempId;
    // Find all elements with a class name of RoundedCorners
    var arrElements = document.getElementsByTagName('*');
    var oRegExp = new RegExp("(^|\\s)RoundedCorners(\\s|$)");
    for (var i=0; i<arrElements.length; i++) {
      // Save the original outer element for later
      oElement = arrElements[i];
      if (oRegExp.test(oElement.className)) {
        //   Create a new element and give it the original element's class name(s) while replacing 'cbb' with 'cb'
        oOuter = document.createElement('div');
        oOuter.className = oElement.className.replace(oRegExp, '$1cb$2');
        // Give the new div the original element's id if it has one
        if (oElement.getAttribute("id")) {
          tempId = oElement.id;
          oElement.removeAttribute('id');
          oOuter.setAttribute('id', '');
          oOuter.id = tempId;
        }
        // Change the original element's class name and replace it with the new div
        oElement.className = 'i3';
        oElement.parentNode.replaceChild(oOuter, oElement);
        // Create two new div elements and insert them into the outermost div
        oI1 = document.createElement('div');
        oI1.className = 'i1';
        oOuter.appendChild(oI1);
        oI2 = document.createElement('div');
        oI2.className = 'i2';
        oI1.appendChild(oI2);
        // Insert the original element
        oI2.appendChild(oElement);
        // Insert the top and bottom divs
        cbb.insertTop(oOuter);
        cbb.insertBottom(oOuter);
      }
    }
  },
  insertTop : function(obj) {
    var oOuter, oInner;
    // Create the two div elements needed for the top of the box
    oOuter=document.createElement("div");
    oOuter.className="bt"; // The outer div needs a class name
      oInner=document.createElement("div");
      oOuter.appendChild(oInner);
    obj.insertBefore(oOuter,obj.firstChild);
  },
  insertBottom : function(obj) {
    var oOuter, oInner;
    // Create the two div elements needed for the bottom of the box
    oOuter=document.createElement("div");
    oOuter.className="bb"; // The outer div needs a class name
      oInner=document.createElement("div");
      oOuter.appendChild(oInner);
    obj.appendChild(oOuter);
  },
  // addEvent function from http://www.quirksmode.org/blog/archives/2005/10/_and_the_winner_1.html
  addEvent : function(obj, type, fn) {
    if (obj.addEventListener)
      obj.addEventListener(type, fn, false);
    else 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]);
    }
  }
};

// Registers the cbb initializer with the onLoad event.
cbb.addEvent(window, 'load', cbb.init);

function clearSelected() {
  var messageFrame = document.getElementById("MessageFrame");
  var idsSelected = getListSelection();
  var deletdItems = 1;

  if (idsSelected.push) {
    deletdItems = idsSelected.length;
    for (var i = 0; i < idsSelected.length; i++) {
      var rowId = idsSelected[i]
      if (selectedRows[rowId].parentNode) {
        deleteListRowById(rowId, true);
      }
    }
  } else {
    deleteListRowById(idsSelected, true);
  }

  deselectAll();
  updateRowColors();
  return deletdItems;
}

function setMaxPerList( val ) {
  var maxPulldownObj = document.getElementById("MaxPerListPulldown");
  if(maxPulldownObj) {
    for (i=0; i<maxPulldownObj.options.length; i++) {
      if (maxPulldownObj.options[i].value == val) {
        maxPulldownObj.options[i].selected = true;
        break;
      }
    }
  }
}

function setFilterByValue ( filter, value ) {
  if (!useNewFilters) {
    obj = toolbarRegistry.filterObjects[filter];
    for( i=0; obj.length>i; i++ ) {
      if ( obj[i].value == value ) {
        obj[i].selected = true;
        break;
      }
    }
  } else {
    var filterLabel = document.getElementById(filter + "Label");
    var filterLookup = toolbarRegistry.filterLookups[filter];
    var filterGroup = toolbarRegistry.filters[filter];

    var valueText = filterLookup[value];
    filterLabel.childNodes[1].data = valueText;
  }
  searchOptions.selectedFilters[filter] = value;
}

function resetSearchBox() {
  var searchBox = document.getElementById("SearchBox");
  searchBox.style.color = "#888";
  searchBox.value = "Search Below";
  searchOptions.searchText = "";
}

function deleteOptions( selectObj ) {
  while (selectObj[0]) {
    selectObj[0] = null;
  }
}

function drawFolderOptions(folderList, selObj, indent, selectedValue) {
  if (!folderList.push) {
    folderList = new Array(folderList);
  }
  indent = indent || 0;

  for (var i = 0; i < folderList.length; i++) {
    var thisFolder = folderList[i];
    var newOpt = document.createElement("option");

    if (!ie) {
      var newImg = document.createElement("img");

      newImg.src = defaultClosed;
      newImg.style.paddingRight = "0.5em"
      newOpt.appendChild(newImg);
      newOpt.innerHTML += thisFolder["name"];
      newOpt.value = thisFolder["id"];
      newOpt.style.paddingLeft = (indent * 2) + "em";
    } else {
      // IE
      for (var x = 0; x < (indent * 2); x++) {
        newOpt.innerHTML += "--"
      }
      newOpt.innerHTML += thisFolder["name"];
      newOpt.value = thisFolder["id"];
    }

    if (selectedValue && selectedValue == thisFolder["id"]) {
      newOpt.selected = true;
    }
    
    selObj.appendChild(newOpt);

    if (thisFolder.subFolders) {
      drawFolderOptions(thisFolder.subFolders, selObj, indent + 1, selectedValue);
    }
  }

  selObj.loaded = true;
}

function getElement (ev) {
  if (document.all) {
    return window.event.srcElement;
  } else {
    return ev.currentTarget;
  }
}


/********************************************
  *******************************************
  SS_Tree CLASS                             *
  *******************************************
 ********************************************/

SS_Tree = function( container, name, dropable, separator ) {
  this.name        = name;
  this.dropable    = dropable;
  this.container   = container;
  this.treeData    = new Object;
  this.singleClick = function() {};
  this.doubleClick = function() {};
  this.onOpen      = function() {};
  this.onClose     = function() {};
  this.selectedRow = "";
  if (separator) {
    this.separator = separator;
  } else {
    this.separator = "/";
  }
};

SS_Tree.prototype.setSingleClick = function(func) {
  this.singleClick = func;
};

SS_Tree.prototype.setDoubleClick = function(func) {
  this.doubleClick = func;
};

SS_Tree.prototype.setOnOpen = function(func) {
  this.onOpen = func;
};

SS_Tree.prototype.setOnClose = function(func) {
  this.onClose = func;
};

SS_Tree.prototype.drawTree = function(data) {
  if (!data) {
    return;
  }  
  this.clearTree();
  if (data.length == undefined) {
    this.drawTreeRoot(data);
  } else {
    for (var i = 0; i < data.length; i++) {
      this.drawTreeRoot(data[i]);
    }
  }
};

SS_Tree.prototype.clearTree = function() {
  this.treeData = new Object();
  var freeSpaceObj = "";
  while (this.container.firstChild) {
    if(this.container.firstChild.id == "FreeSpace") {
      freeSpaceObj = this.container.firstChild;
    }
    this.container.removeChild(this.container.firstChild);
  }

  if ( freeSpaceObj ) {
    this.container.appendChild(freeSpaceObj);
  }
}

SS_Tree.prototype.drawTreeRoot = function(data) {
  if (this.name == "main" ) {
    this.treeData[data["id"]] = data;
  } else {
    this.treeData[data["id"]] = new Object();
    for ( key in data ) {
      if (key == "subFolders") {
        this.treeData[data["id"]][key] = new Array();
        for (subkey in data[key]) {
          this.treeData[data["id"]][key][subkey] = data[key][subkey];
        }
      } else {
        this.treeData[data["id"]][key] = data[key];
      }
    }
  }
  
  var childCount = 0;
  if (data["subFolders"] && data["subFolders"].length > 0) {
    childCount = data["subFolders"].length;
    if (childCount == undefined) {
      childCount = 1;
    }
  }
  var subContainer = this.drawTreeRow(data["id"], data["name"], this.container,
                                      data["description"], data["folderIcon"],
                                      childCount, "", data["folderIconWidth"],
                                      data["folderIconHeight"]);
   this.doSubFolders(data, subContainer);
};

SS_Tree.prototype.doSubFolders = function(subNode, subContainer) {
    if (!subNode["subFolders"] || subNode["subFolders"] == undefined || subNode["subFolders"].length == 0) {
      return;
    } else if (!subNode["subFolders"].length) {
      subNode["subFolders"] = new Array(subNode["subFolders"]);
    }

    for (var i = 0; i < subNode["subFolders"].length; i++) {
      var row = subNode["subFolders"][i];
      var childCount = 0;
      
      if (row["subFolders"] != undefined) {
        if (row["subFolders"].length == undefined) {
          row["subFolders"] = new Array(row["subFolders"]);
        }
        childCount = row["subFolders"].length;
      }
      
      var folderObj = new Object();
      for ( key in row ) {
        folderObj[key] = row[key]; 
      }
      
      if ( this.name == "main" ) {
        this.treeData[row["id"]] = row;
      } else {
        // We cannot set the old object equal to new object and we need to copy it.
        this.treeData[row["id"]] = new Object();
        for ( key in row ) {
          this.treeData[row["id"]][key] = row[key]; 
        }
      }
      
      var subSubContainer = this.drawTreeRow(row["id"], row["name"], subContainer,
                                             row["description"], row["folderIcon"],
                                             childCount, "", row["folderIconWidth"],
                                             row["folderIconHeight"]);

      if (row["subFolders"] && row["subFolders"].length > 0) {
        this.doSubFolders(row, subSubContainer);
      }
    }
};


SS_Tree.prototype.drawTreeRow = function(id, name, parent, description, icon, hasChildren, nextFolderObj, iconWidth, iconHeight) {
  var thisTree = this;
  defaultClosed = imagesURL + "/iconset/ss_small_folder_closed.png";
  defaultOpen = imagesURL + "/iconset/ss_small_folder_open.png";

  if (!icon) { 
    icon = defaultClosed;
    iconWidth = 16;
    iconHeight = 15;
  } else if (icon.indexOf("http") == 0) {
    icon = icon;
  } else {
    icon = imagesURL + icon;
  };

  var container = document.createElement("div");
  container.id = id + "_Container" + this.name;
  container.rowId = id;
  container.className = "FolderRow";
  container.onmouseover = highlightTreeRow;
  container.onmouseout = unhighlightTreeRow;
  //container.onclick = treeRowClicked;
 
  var newImg = document.createElement("img");
  newImg.childCount = hasChildren;
  if (hasChildren) {
    newImg.src = imagesURL + "/iconset/ss_widget_expand.png";
    newImg.onclick = function() { thisTree.expandTreeRow(this) };
    newImg.width = 16;
    newImg.height = 16;
  } else {
    newImg.src = imagesURL + "/filemanager/ftv2blank.gif";
    newImg.width = 16;
    newImg.height = 16;
  }
  newImg.style.verticalAlign = "bottom";
  container.appendChild(newImg);

  var folderImgSpan = document.createElement("span");
  var newImg = document.createElement("img");
  newImg.src = icon;
  if (iconWidth) {
    newImg.width = iconWidth;
  }
  if (iconHeight) {
    newImg.height = iconHeight;
  }
  newImg.closedIcon = icon; // For opening/closing.
  folderImgSpan.className = "FolderIcon";
  folderImgSpan.onclick = function() {thisTree.selectTreeFolder(this)} ;

  folderImgSpan.appendChild(newImg);
  container.appendChild(folderImgSpan); 

  folderNameSpan = document.createElement("span");
  folderNameSpan.id = id + "_Name" + this.name;
  folderNameSpan.className = "FolderName";
  tn = addText(name, folderNameSpan);
  folderImgSpan.appendChild(folderNameSpan);
  if (description && description != "") {
    tn.tipId = id + "Tip";
    if (tn.attachEvent) {
      // For IE
      tn.attachEvent("onmouseover", openGenericTip);
    } else {
      // For Firefox
      tn.addEventListener("mouseover", openGenericTip, false);
    }
    tn.onmouseout = closeGenericTip;
    createToolTip(tn.tipId, description);
  }

  if( nextFolderObj ) {
    parent.insertBefore( container, nextFolderObj );
  } else {
    parent.appendChild(container);
  }

  if ( this.dropable ) {
    treeDroppables.push(container); 
  }

  var subContainer = document.createElement("div");
  subContainer.id = id + "_Contents" + this.name;
  subContainer.folderId = id;
  subContainer.className = "FolderContents";
  subContainer.style.display = "none";

  if (nextFolderObj) {
    parent.insertBefore( subContainer, nextFolderObj );
  } else {
    parent.appendChild(subContainer);
  }  
  return subContainer;
};


SS_Tree.prototype.openTreeFolder = function(folderId, noClick, noSelect, setFocus) {
  var folderContents = document.getElementById(folderId + "_Contents" + this.name);
  var folderName = document.getElementById(folderId + "_Name" + this.name);

  if (!folderContents) {
    return;
  }

  if (folderContents.style.display == "none") {
    this.toggleFolder(folderId, noClick);
    removeClassModifier(folderName, "Unread");
  } else {
    var rowData = this.treeData[folderId];

    if (!noClick) {
      this.singleClick(rowData);
    }
  }

  if (!noSelect) {
    if (this.selectedRow) {
      this.unselectTreeRow(this.selectedRow);
    }

    this.selectTreeRow(folderId);
    this.selectedRow = folderId;
    
    if (setFocus) {
      if (this.container.parentNode.style.height) {
        var scrollObj = this.container.parentNode;
      } else if (this.container.parentNode.parentNode.style.height) {
        var scrollObj = this.container.parentNode.parentNode;
      } else {
        var scrollObj = null;
      }

      if (scrollObj) {
        var offTop = Number(folderContents.offsetTop);
        var sctop = Number(scrollObj.scrollTop);
        var scHeight = Number(removePX(scrollObj.style.height));
        if (  offTop > (scHeight + sctop - 25) ) {
          scrollObj.scrollTop = offTop - scHeight + 25;
        }
      }
    }
  }
};


SS_Tree.prototype.selectTreeFolder = function(elm) {
  this.openTreeFolder(elm.parentNode.rowId);
};

SS_Tree.prototype.expandTreeRow = function (elm) {
  this.toggleRowState(elm.parentNode, true);
}

SS_Tree.prototype.selectTreeRow = function(folderId) {
  var folderName = document.getElementById(folderId + "_Name" + this.name);
  removeClassModifier(folderName, "OverBg");
  addClassModifier(folderName, "SelectedBg");
}

SS_Tree.prototype.unselectTreeRow = function (folderId) {
  var folderName = document.getElementById(folderId + "_Name"  + this.name);
  if (folderName) {
    removeClassModifier(folderName, "SelectedBg");
    removeClassModifier(folderName, "SelectedInactiveBg");
  }
}

SS_Tree.prototype.toggleFolder = function (folderId, noClick) {
  var folderRow = document.getElementById(folderId + "_Container" + this.name);
  var folderContents = document.getElementById(folderId + "_Contents" + this.name);

  var openFolder = false;
  if (folderContents.style.display == "none") {
    openFolder = true;
  }

  if (folderRow) {
    this.toggleRowState(folderRow, noClick);
  }

  var done = false;
  if (openFolder) {
    do {
      rowParent = folderRow.parentNode;
      if (rowParent.className != "FolderContents") {
        done = true;
        break;
      } else {
        folderRow = rowParent.previousSibling;
        if (rowParent.style.display == "none") {
          this.toggleRowState(folderRow, true);
        }
      }
    } while (!done);
  }
}

SS_Tree.prototype.toggleRowState = function (folderRow, noClick) {
  var rowData = this.treeData[folderRow.rowId];
  var contents = folderRow.nextSibling;
  var name = document.getElementById(folderRow.rowId + "_Name" + this.name);
  var bulletImg = folderRow.firstChild;
  var folderImg = bulletImg.nextSibling;

  if (!noClick) {
    this.singleClick(rowData);
  }

  if (contents.style.display == "none") {
    if (folderImg.src == defaultClosed) {
      folderImg.src = defaultOpen;
    }
    if (bulletImg.childCount) {
      bulletImg.src = imagesURL + "/iconset/ss_widget_contract.png";
    }
    contents.style.display = "block";
    this.onOpen(rowData);
    if ( (name.firstChild.innerHTML).indexOf("(") == -1) {
      removeClassModifier(name, "Unread");
    }
  } else {
    if (folderImg.src == defaultOpen) {
      folderImg.src = defaultClosed;
    }
    if (bulletImg.childCount) {
      bulletImg.src = imagesURL + "/iconset/ss_widget_expand.png";
    }
    contents.style.display = "none";
    this.onClose(rowData);
    if (this.folderHasUnread(folderRow.rowId)) {
      addClassModifier(name, "Unread");
    }
  }
}

SS_Tree.prototype.insertTreeRow = function (newFolderName, parentId) {
  var destContainer = document.getElementById(parentId + "_Contents"  + this.name);
  var destFolderRow = document.getElementById(parentId + "_Container" + this.name);
  if(this.separator == "/") {
    if (parentId == "/") {
      var newFolderId = "/" + newFolderName;
    } else {
      var newFolderId = parentId + "/" + newFolderName;
    }  
  } else {
    var newFolderId = parentId + "." + newFolderName;
  } 

  var newFolderObj = new Object();
  newFolderObj.id = newFolderId ;
  newFolderObj.name = newFolderName;
  var parentFolderObj = this.treeData[parentId];

  if (!parentFolderObj) {
    return;
  }

  if (parentFolderObj.subFolders && parentFolderObj.subFolders != "") {
    nextFolderObj = this.getNextFolder ( parentFolderObj.subFolders, newFolderName, parentId);
    parentFolderObj.subFolders = insertItemToArray(parentFolderObj.subFolders, newFolderObj, nextFolderObj.pos );
  } else {
    parentFolderObj.subFolders = new Array(newFolderObj);
    var widgetImg = destFolderRow.firstChild;
    if( destContainer.style.display == "block") {
      widgetImg.src = imagesURL + "/iconset/ss_widget_contract.png";
    } else {
      widgetImg.src = imagesURL + "/iconset/ss_widget_expand.png";
    }
    widgetImg.width = 16;
    widgetImg.height = 16;
    var thisTree = this;
    widgetImg.onclick = function() { thisTree.expandTreeRow(this) };
    widgetImg.childCount = 1;
    nextFolderObj = false;
  }
  this.drawTreeRow(newFolderId, newFolderName, destContainer, "", "", "", nextFolderObj);
  this.treeData[newFolderId] = newFolderObj;
  treeDataUpdated = true;
}


SS_Tree.prototype.treeRowExists = function (newFolderName, parentId) {
  if(this.separator == "/") {
    if (parentId == "/") {
      var newFolderId = "/" + newFolderName;
    } else {
      var newFolderId = parentId + "/" + newFolderName;
    }  
  } else {
    var newFolderId = parentId + "." + newFolderName;
  }
  var destContainer = document.getElementById(newFolderId + "_Contents" + this.name);
  if (destContainer) {
    return true;
  } else {
    return false;
  }
}

SS_Tree.prototype.deleteTreeRow = function (rowId) {
  var treeRow = document.getElementById(rowId + "_Container" + this.name);
  var treeRowContents = document.getElementById(rowId + "_Contents"  + this.name);

  if (this.separator == "/") {
    var parentId = rowId.substr(0, rowId.lastIndexOf("/") ); 
    if (!parentId) {
      parentId = "/";
    }
  } else {
    var parentId = rowId.substr(0, rowId.lastIndexOf(".") ); 
  }

  var parentFolderRow = document.getElementById(parentId + "_Container" + this.name);
  var parentFolderObj = this.treeData[parentId];

  delete this.treeData[rowId];
  treeDataUpdated = true;
  treeRow.parentNode.removeChild(treeRow);
  treeRowContents.parentNode.removeChild(treeRowContents);

  pos = "";
  for ( i=0; i<parentFolderObj.subFolders.length; i++ ) {
    folderObj = parentFolderObj.subFolders[i];
    if ( folderObj.id == rowId ) {
      pos = i;
      break;
    }
  }
  parentFolderObj.subFolders.splice(pos,1);
  if (parentFolderObj.subFolders.length == 0 ) {
    parentFolderObj.subFolders = "";
    var widgetImg = parentFolderRow.firstChild;
    widgetImg.src = imagesURL + "/filemanager/ftv2blank.gif";
    widgetImg.onclick = null;
    widgetImg.childCount = 0;

  }
}


SS_Tree.prototype.renameTreeRow = function(newFolderName, oldId) {
  
  var targetRow = document.getElementById(oldId + "_Container" + this.name);
  var targetContents = document.getElementById(oldId + "_Contents" + this.name);
  var targetNameObj = document.getElementById(oldId + "_Name" + this.name);


  var folderStruct = oldId.split(this.separator);
  var oldFolderName = folderStruct.pop();

  if (folderStruct.length) {
    var parentId = folderStruct.join(this.separator);
    if (!parentId) {
      // it can only happen if oldId is like this /test
      parentId = "/";
    }
  } else {
    var parentId = false;
  }
  
  folderStruct.push(newFolderName);
  var newId = folderStruct.join(this.separator);

  targetRow.rowId = newId;
  targetRow.id = newId + "_Container" + this.name;
  targetNameObj.firstChild.innerHTML = newFolderName;
  targetNameObj.id = newId + "_Name" + this.name;
  targetContents.id = newId + "_Contents" + this.name;

  if (this.selectedRow == oldId) {
    this.selectedRow = newId;
  }

  var rowData = this.treeData[oldId];
  this.treeData[newId] = rowData;
  treeDataUpdated = true;
  this.treeData[oldId] = undefined;

  if (parentId) {
    var parentData = this.treeData[parentId];
    for (var i = 0; i < parentData.subFolders.length; i++) {
      var childData = parentData.subFolders[i];
      if (childData.id == oldId) {
        childData.id = newId;
        childData.name = newFolderName;
        if (childData.subFolders){
          this.changeChildrenIds(childData.subFolders, newId);
        }
        break;
      }
    }
  }
}

SS_Tree.prototype.changeChildrenIds = function (treeObj, newParentId) {
  for (var i = 0; i < treeObj.length; i++) {
    var oldId = treeObj[i].id;
    var folderStruct = oldId.split(this.separator);
    var folderName = folderStruct.pop();
    var folderContainerObj = document.getElementById(oldId + "_Container" + this.name);
    var folderContentsObj = document.getElementById(oldId + "_Contents" + this.name);
    var folderNameObj = document.getElementById(oldId + "_Name" + this.name);
    var newId = newParentId + this.separator + folderName;
    treeObj[i].id = newId;
    this.treeData[newId] = this.treeData[oldId];
    this.treeData[oldId] = undefined;
    if (folderContainerObj){
      folderContainerObj.id = newId + "_Container" + this.name;
      folderContainerObj.rowId = newId;
    }
    if (folderContentsObj) {
      folderContentsObj.id = newId + "_Contents" + this.name;
    }
    if (folderNameObj) {
      folderNameObj.id = newId + "_Name" + this.name;
    }
    if(treeObj[i].subFolders){
      this.changeChildrenIds(treeObj[i].subFolders, treeObj[i].id);
    }
  }
}

SS_Tree.prototype.copyTreeRow = function (rowId, destId) {
  var rowId = rowId.replace(/\\\//g, "/");
  
  if (this.separator == "/") {
    var lastSlashPos = rowId.lastIndexOf("/");
    var folderName = rowId.substr( lastSlashPos + 1 );
  } else {
    var lastDotPos = rowId.lastIndexOf(".");
    var folderName = rowId.substr( lastDotPos + 1 );
  }
  this.insertTreeRow( folderName, destId);

  var treeObj = this.treeData[rowId];   
  if (treeObj.subFolders) {
    for ( k in treeObj.subFolders) {
      if(this.separator == "/") {
        if (destId == "/") {
          var newDestId = "/" + folderName;
        } else {
          var newDestId = destId + "/" + folderName; 
        }
      } else {
        var newDestId = destId + "." + folderName;
      }
      this.copyTreeRow( treeObj.subFolders[k].id, newDestId );
    }
  }
}


SS_Tree.prototype.moveTreeRow = function (rowId, destId) {
  var rowId = rowId.replace(/\\\//g, "/");   
  this.copyTreeRow( rowId, destId );
  this.deleteTreeRow(rowId);
}

SS_Tree.prototype.inactivateFolder = function ( numSelected ) {
  var folderName = document.getElementById(this.selectedRow + "_Name" + this.name);
  if (folderName) {
    if(numSelected){
      removeClassModifier(folderName, "SelectedBg");
      addClassModifier(folderName, "SelectedInactiveBg");
    } else {
      removeClassModifier(folderName, "SelectedInactiveBg");
      addClassModifier(folderName, "SelectedBg");
    }
  }
}

SS_Tree.prototype.getNextFolder = function ( subFolders, newFolderName, parentId ) {
  try {
    var folderNames = new Array(newFolderName);
    for ( i=0; i<subFolders.length; i++ ) {
      subFolderName = subFolders[i].name;
      if ( parentId == "INBOX" ) {
        if (!( subFolderName == "Drafts" || 
               subFolderName == "Sent" || 
               subFolderName == "Junk" || 
               subFolderName == "Trash" ) ) {
          folderNames.push( subFolderName );
        }
      } else {
        folderNames.push( subFolderName );
      }  
    }
    folderNames.sort(charOrdA);
    
    var folderPos = indexOf( folderNames, newFolderName);
    if ( folderPos < subFolders.length ) {
      nextFolderName = folderNames[folderPos + 1];
      for ( i=0; i<subFolders.length; i++ ) {
        if (subFolders[i].name == nextFolderName ) {
          nextFolderObj = document.getElementById( subFolders[i].id + "_Container" + this.name);
          nextFolderObj.pos = i;
          return nextFolderObj;
        }
      }
    }
  } catch(e) {}  
  return false;
}

SS_Tree.prototype.boldTreeRows = function(data) {
  var folderList = data.unread_count;
  if (folderList) {
    if (!folderList.push) {
      folderList = new Array(folderList);
    }

    for (var i = 0; i < folderList.length; i++) {
      var folderData = folderList[i];
      var id = folderData["path"];
      var parentId = id.substr(0, id.lastIndexOf(this.separator) );
      if ( id != this.selectedRow ) {
        var folderName = document.getElementById(id + "_Name" + this.name);
        if ( folderName ) {
          if (folderData.unseen > 0 ) {
            addClassModifier(folderName, "Unread");
            folderName.firstChild.innerHTML = folderData["name"] + " (" + folderData.unseen + ")";
          } else {
            removeClassModifier(folderName, "Unread");
            folderName.firstChild.innerHTML = folderData["name"];
          }
        }
        if ( parentId && folderData.unseen > 0) {
          this.boldParents(parentId);
        }  
      }  
    }
  }
}


SS_Tree.prototype.boldParents = function(id) {
  var folderName = document.getElementById(id + "_Name" + this.name);
  var folderContents = document.getElementById(id + "_Contents" + this.name);
  var folderContainerObj = document.getElementById(id + "_Container" + this.name);
  if (!folderName || folderContents.style.display == "block") {
    return;
  } else {
    addClassModifier(folderName, "Unread");
    var parentId = id.substr(0, id.lastIndexOf(this.separator) );
    if ( parentId && parentId != "INBOX" ) {
      this.boldParents(parentId);
    }
  }  
}

SS_Tree.prototype.updateUnseen = function(unreadNumbers, id) {
  if (!id) {
    id = this.selectedRow;
  }
  folderObj = document.getElementById(id + "_Name" + this.name);
  if ( !folderObj ) return;
  folderName = id.substr(  id.lastIndexOf(this.separator) + 1  );
  if (folderName) {
    if ( unreadNumbers > 0 ) {
      addClassModifier(folderObj, "Unread");        
      folderObj.firstChild.innerHTML = folderName + " (" + unreadNumbers + ")";
    } else {
      removeClassModifier(folderObj, "Unread");
      folderObj.firstChild.innerHTML = folderName ;
    }
  }
}

SS_Tree.prototype.folderHasUnread = function(folderId) {
  var hasUnread = false;

  var folderName = document.getElementById(folderId + "_Name" + this.name);
  var folderData = this.treeData[folderId];

  if (!folderName || folderName.className.indexOf("Unread") > -1) {
    return true;
  }

  if (folderData.subFolders) {
    for (var i = 0; i < folderData.subFolders.length; i++) {
      var subFolderPath = folderId + "." + folderData.subFolders[i].name;
      hasUnread = this.folderHasUnread(subFolderPath);
      if (hasUnread) {
        return hasUnread;
      }
    }
  }

  return hasUnread;
}

SS_Tree.prototype.getFolderNameObj = function(folderId) {
  return document.getElementById(folderId + "_Name" + this.name);
}


/*
 *  end of SS_Tree class
 */
 
function ss_drawLine(x1, y1, x2, y2, className, id) {
  var sc = document.getElementById("ScrollableContent");
  var lineContainer = document.createElement("div");
  lineContainer.id = "line_" + id;
  lineContainers.push(lineContainer);

  if (x1 > x2) {
    var _x2 = x2;
    var _y2 = y2;
    x2 = x1;
    y2 = y1;
    x1 = _x2;
    y1 = _y2;
  }
  var dx = x2 - x1;
  var dy = Math.abs(y2 - y1);
  var x = x1;
  var y = y1;
  var yIncr = 1;
  if (y1 > y2) {
    yIncr = -1;
  }

  drw = true;
  if(dx >= dy) {
    var pr = dy << 1;
    pru = pr - (dx << 1);
    p = pr - dx;
    while(dx > 0) {
      --dx;
      if(drw) {
        ss_drawDiv(x, y, 2, 2);
      }
      drw = !drw;
      if (p > 0) {
        y += yIncr;
        p += pru;
      } else {
        p += pr;
      }
      ++x;
    }
  } else {
    var pr = dx << 1,
    pru = pr - (dy << 1),
    p = pr-dy;
    while(dy > 0) {
      --dy;
      if(drw) {
        ss_drawDiv(x, y, 2, 2);
      }
      drw = !drw;
      y += yIncr;
      if(p > 0) {
        ++x;
        p += pru;
      } else {
        p += pr;
      }
    }
  }
  if(drw) {
    ss_drawDiv(x, y, 2, 2);
  }
  sc.appendChild(lineContainer);

  function ss_drawDiv(x, y, w, h) {
    var div = document.createElement("div");
    div.style.position = "absolute";
    div.style.left = x  + "px";
    div.style.top = y  + "px";
    div.style.width = w + "px";
    div.style.height =  h + "px";
    div.style.clip = "rect(0," + w + "px," + h + "px,0)";
    div.className = className;
    lineContainer.appendChild(div);
  }
  return lineContainer;
}

function ss_clearLine( obj, all ) {
   for ( i=lineContainers.length-1; i>=0; i--) {
     if (all) {
       lineContainers[i].parentNode.removeChild(lineContainers[i]);
       lineContainers.splice(i, 1);
     } else if (lineContainers[i].id != "line_Selected" ) {
       lineContainers[i].parentNode.removeChild(lineContainers[i]);
       lineContainers.splice(i, 1);
     }
   }
   if (all) {
     selectedObj = null;
   }
 }

function ss_showCoverFrame() {
  document.getElementById("CoverFrame").style.visibility = "visible";
}

function ss_hideCoverFrame() {
  document.getElementById("CoverFrame").style.visibility = "hidden";
}

function copyDirectoryField(dest, origin, type) {
  if (type == "address"   || 
      type == "usAddress" ||
      type == "fullName"  ||
      type == "date"  ) {
    for (i=1; 7 > i; i++) {
      var originObj = document.getElementById(origin + "_" + i);
      if (originObj) {
        document.getElementById(dest + "_" + i).value = originObj.value;
      }
    }
  } else if (type == "checkbox") {
    if( document.getElementById(origin).checked) {
      document.getElementById(dest).checked = true;
    } else {
      document.getElementById(dest).checked = false;
    }
  } else if (type == "gender") {
    if( document.getElementById(origin + "_1").checked) {
      document.getElementById(dest + "_1").checked = true;
    }
    if( document.getElementById(origin + "_2").checked) {
      document.getElementById(dest + "_2").checked = true;
    }
  } else {
    document.getElementById(dest).value = document.getElementById(origin).value;
  }
}

function setpublishSpec(fieldName,fieldType, val ) {
  if (fieldType == "fullName") {
    var len = 3;
  } else if (fieldType == "usAddress") {
    var len = 5;
  } else if (fieldType == "address") {
    var len = 6;
  } else {
    return;
  }
  for (i=0; len>=i; i++) {
    var obj = document.getElementById(fieldName + "_" + i + ".publishSpec");
    if (obj) {
      obj.value = val;
    }
  }
  
}

function showFileUploadAttachment() {
  fileUploadNewClass.openAttachDiv();
}

// For new frame tabs.
var loadedTabs = new Object;
var newTabCallbacks = new Array;
var closeTabCallbacks = new Array;

function onNewTab(func) {
  newTabCallbacks.push(func);
}

function onCloseTab(func) {
  closeTabCallbacks.push(func);
}

function openTabbedURLInIFrame(iframe, url) {
  iframe.onload = null;
  if (iframe.src != url) {
    iframe.src = url;
  }
}

function hideTabContextMenu() {
  SS_ContextMenus.closeAll();
}

var clickedTab;

function openRenameTabDialog() {
  var tab = SS_ContextMenus.target;
  if (tab.nodeName == "SPAN") {
    tab = tab.parentNode;
  }

  var tabA = tab.firstChild;
  var parts = tabA.href.split("#");
  var tabID = parts[parts.length - 1].slice(0, -4);

  var nameField = document.getElementById("NewTabName");
  if (nameField) {
    nameField.value = tabA.innerHTML;
  }
  var idField = document.getElementById("RenameTabID");
  idField.value = tabID;
  showPopup("RenameTabPopup");
  clickedTab = tabA;
}

function duplicateTab() {
  var tab = SS_ContextMenus.target;
  if (tab.nodeName == "SPAN") {
    tab = tab.parentNode;
  }

  var tabA = tab.firstChild;
  var parts = tabA.href.split("#");
  var tabID = parts[parts.length - 1].slice(0, -7);

  var frameDiv = document.getElementById(tabID + "Frame");
  var frame = frameDiv.firstChild;

  createNewTab(tabA.innerHTML, frame.src);
}

function reloadTab() {
  var tab = SS_ContextMenus.target;
  if (tab.nodeName == "SPAN") {
    tab = tab.parentNode;
  }

  var tabA = tab.firstChild;
  var parts = tabA.href.split("#");
  var tabID = parts[parts.length - 1].slice(0, -7);

  var frameDiv = document.getElementById(tabID + "Frame");
  var frame = frameDiv.firstChild;

  frame.contentWindow.location.reload();
}

function showPermTab(event, tabId) {
  var tab = document.getElementById(tabId);

  if (!event) {
    event = window.event;
  }

  var tabObj = new Object;
  tabObj.tab = tab;
  tabObj.panel = {"id" : tab.href.split('#')[1]}

  showTabbedFrame(event, tabObj);

  tab.style.paddingBottom = "0px";

  return false;
}


function hideTabbedFrame(name) {
  var tabContainer = document.getElementById(name + "Frame");
  if (tabContainer) { // It may have been deleted.
    tabContainer.style.display = "none";
  }

  return false;
}

function showTabbedFrame(event, tab) {
  tab.tab.blur(); // Gets rid of the dotted line around the tab.

  $('.ui-tabs-selected').toggleClass('ui-tabs-selected');
  addClassModifier(tab.tab.parentNode, "ui-tabs-selected");
  
  var name = tab.panel.id.replace(/Content/i, "");
  var tabContainer = document.getElementById(name + "Frame");
  if (!tabContainer) return; // The frames aren't drawn yet...
  var iFrame = tabContainer.firstChild;

  if (name == activeTab) {
    // No need to do anything if the tab you clicked is the active tab.
    return;
  }

  if (loadedTabs[name] != true) {
    openTabbedURLInIFrame(iFrame, loadedTabs[name]);
    loadedTabs[name] = true;
  }

  tabContainer.style.display = "block";
  if (activeTab) {
    hideTabbedFrame(activeTab);
  }

  activeTab = name;

  if (iFrame.src.indexOf("/dashboard/desktop.pyt") >= 0) {
    var isDesktop = true;
  }

  var appMenu = document.getElementById("AppMenu");
  for (var i = 0; i < appMenu.childNodes.length; i++) {
    var opt = appMenu.childNodes[i];
    switch (opt.firstChild.data) {
      case "Create Shortcut...":
      case "Place a file on desktop...":
      case "Options...":
      case "Trash":
        if (isDesktop) {
          removeClassModifier(opt, "disabled");
        } else {
          addClassModifier(opt, "disabled")
        }
    }
  }
}

function getOpenTabContent() {
  var frameContainer = document.getElementById(activeTab + "Frame");
  var iFrame = frameContainer.firstChild;

  return iFrame.contentWindow;
}

function drawNewFrameTab(id, name, url, focus) {
  var sc = document.getElementById("ScrollableContent");
  var ft = document.getElementById("FixedTop");
  var tabFrameContainer = document.createElement("DIV");
  var tabFrame = document.createElement("IFRAME");
  var fakeTabFrame = document.createElement("DIV");
  
  tabFrameContainer.id = id + "Frame"
  tabFrameContainer.style.display = "none";
  tabFrame.style.height = "100%";
  tabFrame.style.width = "100%";
  tabFrame.frameBorder = "0";
  tabFrameContainer.appendChild(tabFrame);
  fakeTabFrame.id = id + "Content";
  sc.appendChild(tabFrameContainer);
  ft.appendChild(fakeTabFrame);

  loadedTabs[id] = url;
  $tabs.tabs('add', '#' + id + 'Content', name);

  for (var i = 0; i < newTabCallbacks.length; i++) {
    var callback = newTabCallbacks[i];
    callback(name, url);
  }

  $('.ui-tabs-close').attr("title", "Open Menu");
  $('.ui-tabs-close').unbind('click').click(function(event){
    event = event || window.event;
    var icon = this;
    if (window.event && window.event.srcElement) {
      icon = window.event.srcElement;
    }
  
    SS_ContextMenus.openMenu(event, icon, "DesktopTabs");
  });

  $('.stWidthChecker li').bind('contextmenu', openTabsContextMenu);
}

function tabDeleted(data) {
  // Do nothing for now.
}

function closeTab() {
  var tab = SS_ContextMenus.target;
  if (tab.nodeName == "SPAN") {
    tab = tab.parentNode;
  }

  var tabContainer = tab.parentNode;
  
  for (var i = 0; i < tabContainer.childNodes.length; i++) {
    if (tab == tabContainer.childNodes[i]) {
      $('#Tabs').tabs("remove", i);
    }
  }
}

function closePermanentTab() {
  var tab = SS_ContextMenus.target;
  var tabA = tab.firstChild;
  var parts = tabA.href.split("#");
  var tabID = parts[parts.length - 1].slice(0, -7);
  var delTabCall = new AJAXRequest(tabDeleted);

  tab.parentNode.removeChild(tab);

  var frameContainer = document.getElementById(tabID + "Frame");
  frameContainer.parentNode.removeChild(frameContainer);

  $('#Tabs').tabs("select", 0);

  resizeTabBar();
  makeAJAXCall(delTabCall, "ajax_del_tab.pyt?ID=" + tabID, true);
}

function tabNotPermanent(data) {
  var tab = SS_ContextMenus.target;
  var tabdata = data.tab;

  tab.parentNode.removeChild(tab);

  // Add the tab and make all the required changes.
  $tabs.tabs('add', '#' + tabdata.ID + 'Content', tabdata.description);
  $('.ui-icon-close').toggleClass('ui-icon-close ui-icon-triangle-1-s').attr("title", "Open Menu");
  $('.ui-tabs-close').unbind('click').click(openTabsContextMenu);
  $('.stWidthChecker li').bind('contextmenu', openTabsContextMenu);
  resizeTabBar();
}

function notPermanentTab() {
  var tab = SS_ContextMenus.target;
  var tabA = tab.firstChild;

  var parts = tabA.href.split("#");
  var tabID = parts[parts.length - 1].slice(0, -7);

  var permTabCall = new AJAXRequest(tabNotPermanent);
  makeAJAXCall(permTabCall, "ajax_not_permanent_tab.pyt?ID=" + tabID, true);
}

function tabPermanent(data) {
  var tab = SS_ContextMenus.target;
  if (tab.nodeName == "SPAN") {
    tab = tab.parentNode;
  }

  tab.parentNode.removeChild(tab);

  var tabdata = data.tab;
  var $pTabs = $('#SS_PermanentTabs').tabs();
  $pTabs.tabs('add', '#' + tabdata.ID + "Content", '<img border="0" height="18" width="18" src="' + tabdata.icon + '"/>');
  var newTab = $pTabs[0].firstChild.childNodes[$pTabs[0].firstChild.childNodes.length - 1];
  var newTabLink = newTab.firstChild

  newTab.firstChild.title = tabdata.description;
  SS_ContextMenus.attachMenu("PermanentTabsMenu", newTab);
  newTab.style.textAlign = "center";
  newTabLink.className = "SS_PermanentTabLink";
  newTabLink.style.width = "30px";
  newTabLink.style.padding = "0px";
  newTabLink.style.paddingBottom = "2px";

  resizeTabBar();
}

function permanentTab() {
  var tab = SS_ContextMenus.target;
  if (tab.nodeName == "SPAN") {
    tab = tab.parentNode;
  }

  var tabA = tab.firstChild;

  var parts = tabA.href.split("#");
  var tabID = parts[parts.length - 1].slice(0, -7);
  var permTabCall = new AJAXRequest(tabPermanent);
  
  makeAJAXCall(permTabCall, "ajax_permanent_tab.pyt?ID=" + tabID, true);
}

function closeTabbedFrame(event, tab) {
  var id = tab.panel.id.replace(/Content/i, "");
  var tabContainer = document.getElementById(id + "Frame");
  var delTabCall = new AJAXRequest(tabDeleted);

  tabContainer.parentNode.removeChild(tabContainer);
  delete loadedTabs[id];

  makeAJAXCall(delTabCall, "ajax_del_tab.pyt?ID=" + id, true);

  for (var i = 0; i < closeTabCallbacks.length; i++) {
    var callback = closeTabCallbacks[i];
    callback(name, url);
  }
}

function highlightTabCloser(img) {
  //var img = this || window.event.srcElement;

  img.src = imagesURL + "/templates/tab_delete_highlight.png";
}

function unhighlightTabCloser(img) {
  //var img = this || window.event.srcElement;

  img.src = imagesURL + "/templates/tab_delete.png";
}

function helpApplicationFunc(filter) {
  if (helpApplicationName == "Tasks") {
    var thisCategory = "Tasks or Workflow";
  } else {
    var thisCategory = helpApplicationName
  }
  var helpURL = "/knowledgebase/help/browse.pyt?category=/" + thisCategory;
  
  if (filter == "GETTING_STARTED") {
    if (helpApplicationName == "CRM") {
      helpURL += "&selectedFolder=Getting Started&selectedItem=Users: Getting Started with CRM";
    } else {
      helpURL += "&selectedFolder=Getting Started&selectedItem=Getting Started with " + helpApplicationName;
    }
  } else if (filter == "TIP_OF_THE_DAY") {
    helpURL += "&amp;selectedItem=Tip of the Day";
  }
  openWindow("xxx-large/xx-large", helpURL); 
}

function ss_configureMenuFunc(filter) {
  openWindow("xxx-large/xx-large", ss_configureMenuUrls[filter]);
}

/****************************
 * Customizable Context Menus
 ****************************/

var SS_ContextMenus = {
  menuData:  new Object,
  menus: new Array,
  openMenus: new Array,
  openSubMenus: new Array,
  higlighted: undefined,
  target: undefined,
  addEntry: function(menuID, desc, func, icon) {
    var menu = this.menuData[menuID];
    if (!menu) {
      menu = new Array;
      this.menus.push(menuID);
    };
    menu.push({description: desc, callback: func, type: "entry"});
    this.menuData[menuID] = menu;
  },
  addSubMenu: function(menuID, subID, desc, icon) {
    var menu = this.menuData[menuID];
    if (!menu) {
      menu = new Array;
    };
    menu.push({description: desc, id: subID, type: "submenu"});
    this.menuData[menuID] = menu;
  },
  addSeparator: function(menuID) {
    var menu = this.menuData[menuID];
    if (!menu) { alert("A separator can't be the first item in the menu!") };
    menu.push({description: null, callback: null, type: "separator"});
  },
  attachMenu: function(menuID, object, openEvent) {
    if (!openEvent) {
      ss_attachEvent(object, "contextmenu",
                     function(event) { SS_ContextMenus.openMenu(event, this,
                                                                menuID) });
      ss_attachEvent(object, "click", this.closeAll);
    } else {
      ss_attachEvent(object, openEvent,
                     function(event) { SS_ContextMenus.openMenu(event, this,
                                                                menuID) });
    }
  },
  openMenu: function(event, object, menuID) {
    this.closeAll();
    var pb = document.getElementById("PageBody");

    var x = SS_MousePos.x;
    var y = SS_MousePos.y;

    var menuDiv = document.createElement("DIV");
    menuDiv.style.top = y;
    menuDiv.style.left = x;
    menuDiv.className = "SS_ContextMenu";

    var menuBG = document.createElement("DIV");
    menuBG.id = menuID + "BG";
    menuBG.style.top = y;
    menuBG.style.left = x;
    menuBG.className = "SS_ContextMenuBG TransHeavy";
    
    pb.appendChild(menuDiv);
    pb.appendChild(menuBG);

    var menuData = this.menuData[menuID];
    this.drawMenu(menuID, menuDiv, menuData);
    this.openMenus.push(menuDiv);

    menuBG.style.height = menuDiv.offsetHeight - 8;
    menuBG.style.width = menuDiv.offsetWidth - 8; // -8 for padding and border

    event.cancelBubble = true;
    event.returnValue = false;
    if (event.stopPropagation) { event.stopPropagation() }; 
    if (event.preventDefault) { event.preventDefault() };

    this.target = object;
  },
  highlightEntry: function(entry) {
    entry.className = "SS_ContextEntryHighlighted";
    var openSubmenu = this.openSubMenus[0];

    if (openSubmenu) {
      if (openSubmenu.ss_menuId != entry.parentNode.ss_menuId) {
        this.closeAllSubMenus();
      }
    }
    SS_ContextMenus.highlighted = entry;
  },
  unhighlightEntry: function(entry) {
    entry.className = "SS_ContextEntry";
  },
  openSubMenu: function(parent, subMenuID) {
    this.closeAllSubMenus();

    var pb = document.getElementById("PageBody");
    var parentMenu = parent.parentNode;
    var menuData = this.menuData[subMenuID];

    var x = parentMenu.offsetLeft + parent.offsetLeft + parent.offsetWidth;
    var y = parentMenu.offsetTop + parent.offsetTop;

    var menuDiv = document.createElement("DIV");
    menuDiv.style.top = y;
    menuDiv.style.left = x;
    menuDiv.className = "SS_ContextMenu";

    var menuBG = document.createElement("DIV");
    menuBG.id = subMenuID + "BG";
    menuBG.style.top = y;
    menuBG.style.left = x;
    menuBG.className = "SS_ContextMenuBG TransHeavy";
    
    pb.appendChild(menuDiv);
    pb.appendChild(menuBG);
    
    this.drawMenu(subMenuID, menuDiv, menuData);
    this.openSubMenus.push(menuDiv);

    menuBG.style.height = menuDiv.offsetHeight - 8;
    menuBG.style.width = menuDiv.offsetWidth - 8;
  },
  drawMenu: function(menuID, menu, menuData) {
    menu.ss_menuId = menuID;
    for (var i = 0; i < menuData.length; i++) {
      var entry = menuData[i];
      if (entry.type == "separator") {
        var sep = document.createElement("HR");
        sep.className = "SS_ContextEntrySeparator";
        menu.appendChild(sep);
      } else if (entry.type == "submenu") {
        var entryDiv = document.createElement("DIV");
        entryDiv.className = "SS_ContextEntry";
        entryDiv.innerHTML = entry.description;
        entryDiv.id = menuID + i;
        entryDiv.ss_submenuId = entry.id
        ss_attachEvent(entryDiv, "mouseover",
                       function() {SS_ContextMenus.highlightEntry(this)});
        ss_attachEvent(entryDiv, "mouseout",
                       function() {SS_ContextMenus.unhighlightEntry(this)});
        ss_attachEvent(entryDiv, "mouseover",
                       function(){
                           SS_ContextMenus.openSubMenu(this,
                                                       this.ss_submenuId)
                       });
        var menuIndicator = document.createElement("IMG");
        menuIndicator.className = "SS_ContextSubMenuIndicator";
        menuIndicator.src = imagesURL + "/templates/menu_submenu_arrow.png";
        entryDiv.style.paddingRight = "1em";
        entryDiv.appendChild(menuIndicator);
        menu.appendChild(entryDiv);
      } else {
        var entryDiv = document.createElement("DIV");
        entryDiv.className = "SS_ContextEntry";
        entryDiv.innerHTML = entry.description;
        entryDiv.id = menuID + i;
        ss_attachEvent(entryDiv, "mouseover",
                       function() {SS_ContextMenus.highlightEntry(this)});
        ss_attachEvent(entryDiv, "mouseout",
                       function() {SS_ContextMenus.unhighlightEntry(this)});
        ss_attachEvent(entryDiv, "click", entry.callback);
        ss_attachEvent(entryDiv, "click", SS_ContextMenus.closeAll);
        menu.appendChild(entryDiv);
      }
    }
  },
  closeMenu: function(menu) {
    var menuID = menu.ss_menuId;
    var menuBG = document.getElementById(menuID + "BG");

    menuBG.parentNode.removeChild(menuBG);
    menu.parentNode.removeChild(menu);
  },
  closeAll: function() {
    SS_ContextMenus.closeAllSubMenus();
    for (var i = 0; i < SS_ContextMenus.openMenus.length; i++) {
      var menu = SS_ContextMenus.openMenus[i];
      SS_ContextMenus.closeMenu(menu);
    }

    SS_ContextMenus.openMenus = new Array;
    SS_ContextMenus.highlighted = undefined;
  },
  closeAllSubMenus: function() {
    for (var i = 0; i < SS_ContextMenus.openSubMenus.length; i++) {
      var menu = SS_ContextMenus.openSubMenus[i];
      SS_ContextMenus.closeMenu(menu);
    }

    SS_ContextMenus.openSubMenus = new Array;
  }
}
  
function SS_TrackMouse(event) {
  SS_MousePos = mouseCoords(event)
}

function ss_isValidEmail( email ) {
  /*
    email should be in the format of part1@part2.part3
    part1 and part2 should have at least 1 char and part3 should have at least 2 chars
  */
  if ( email.indexOf(".") == -1 || email.indexOf("@") == -1 ) {
    return false;
  } else {
    var split1 = email.split("@");
    if ( split1.length != 2 ) {
      return false;
    }
    var part1 = split1[0];
    var split2 = (split1[1]).split(".");
    if ( split2.length < 2  ) {
      return false;
    }
    var part2 = split2[0];
    var part3 = split2[1];
    if( part1.length < 1 || part2.length < 1 || part3.length < 2 ) {
      return false;
    }
    return true;
  }
}

function cancelDefaultAction(event) {
  event = event || window.event;
  
  event.cancelBubble = true;
  event.returnValue = false;
  if (event.stopPropagation) { event.stopPropagation() }; 
  if (event.preventDefault) { event.preventDefault() };
}

function doGoogleSearch() {
  var searchBox = document.getElementById("DesktopSearchBox");
    
  var client = "pub-1819381511545425";
  var forid = "1";
  var ie = "ISO-8859-1";
  var ce = "ISO-8859-1";
  var cof = "GALT:#008000;GL:1;DIV:#336699;VLC:663399;AH:center;BGC:FFFFFF;LBGC:336699;ALC:0000FF;LC:0000FF;T:000000;GFNT:0000FF;GIMP:0000FF;FORID:1;";
  var hl = "en";

  var searchURL = "http://www.google.com/custom";
  searchURL += "?q=" + escape(searchBox.value);
  searchURL += "&sa=Search&client=" + client;
  searchURL += "&forid=" + forid;
  searchURL += "&ie=" + ie + "&ce=" + ce;
  searchURL += "&cof=" + escape(cof);
  searchURL += "&hl=" + hl;
  var tabName = "Search: " + searchBox.value;
  createNewTab(tabName, searchURL);
}

function updateSearchText(textbox, focus) {
  if (focus) {
    if (textbox.value == "Google") {
      textbox.value = "";
      textbox.style.fontStyle = "normal";
      textbox.style.fontWeight = "normal";
      textbox.style.color = "black";
    }
  } else {
    if (textbox.value == "") {
      textbox.value = "Google";
      textbox.style.fontStyle = "italic";
      textbox.style.fontWeight = "bold";
      textbox.style.color = "#AAA";
    }
  }
}

/*
 * these two functions are for resending verification email in user signup and 
 * there is a variable that creates the links in automated letters.
 */
function resendSignupVerificationEmail( url ) {
  var verifyCall = AJAXRequest(processResendSignupVerificationEmail);
  makeAJAXCall(verifyCall, url, true);
}

function processResendSignupVerificationEmail(data) {
  if (!data) return;
  if ( data["error"] ) {
    alert(data["error"]);
  } else if ( data["email"] ) {
    alert("A new verification email has been sent to " + data["email"]);
  }
}

function ss_isReturnKey( event ) {
  var keyNo = window.Event ? event.keyCode : e.which;
  if ( keyNo == 13 ) {
    return true;
  } else {
    return false;
  }
}
