///////////////////////////////////////////////////////////////////////////////
// Copyright (C) 1999-2005 Siebel Systems, Inc.  All rights reserved.
///////////////////////////////////////////////////////////////////////////////

// This javascript provides methods to facilitate a view ui based on an xml
// island.  It provides a framework of editors and panels which allow for easy
// creation and manipulation of xml-based ui's

///////////////////////////////////////////////////////////////////////////////
// This function formats a message with inserts. sMsg should include @1 params
// which will be replaced with corresponding arguments from the aArgs array.
// It returns the resulting message
function XUIFormatMessage(sMsg, aArgs)
{
   if (sMsg == null)
      return "";

   var s = sMsg.toString();

   for (var i = 0; i < aArgs.length; ++i)
   {
      var sInsert = "%" + (i+1);
      s = s.replace(sInsert,aArgs[i]);
   }

   return s;
}

//-----------------
function XUIAssert(bExpr, sWhere)
{
   if(!bExpr)
      alert('SAW ASSERT ERROR: ' + sWhere);
}

///////////////////////////////////////////////////////////////////////////////
// DEPRECATED VIEW AND XML ACCESS METHODS - SHOULD BE USING NEW XUI FRAMEWORK
///////////////////////////////////////////////////////////////////////////////

//taking this out for now since it is probably not essential and it does not work for multiple islands on a page
//var s_tXUINQWElement = null;
// should this be taken out too?
var s_tXUIViewElement = null;
//var s_tXUINQWElement = null;
//-----------------
// DEPRECATED - should be using new editor framework - why is this deprecated?
function XUIGetRootXML(sID, tFrame)
{
   var tRootXML;

   if (!sID)
      sID = "idXUI";
   if (!tFrame)
      tFrame = this;

   var tXmlDoc = saw.getXmlIsland(sID, tFrame, tFrame);

   tRootXML = tXmlDoc.selectSingleNode("//nqw");

   if (tRootXML == null)
   {
      alert('Root XML Node nqw not found in island!');
      return false;
   }

   return tRootXML;
}

//-----------------
// DEPRECATED - should be using new editor framework

// This function populates and returns the static view element from the
// XML island
function XUIGetViewXML(sViewType)
{
   if (s_tXUIViewElement != null)
      return s_tXUIViewElement;

   var tNQW = XUIGetRootXML();
   if (sViewType != null)
      s_tXUIViewElement = tNQW ? tNQW.selectSingleNode('saw:view[@xsi:type="' + sViewType + '"]') : null;

   // If we didn't look or didnt find it, any view tag will do
   if(s_tXUIViewElement == null)
      s_tXUIViewElement = tNQW ? tNQW.selectSingleNode('saw:view') : null;

   if(s_tXUIViewElement == null) // shouldn't happen
   {
      alert('No View XML found in Document for ' + sViewType);
      return null;
   }

   return s_tXUIViewElement;
}

///////////////////////////////////////////////////////////////////////////////
// XML Manipulation Helper Functions
///////////////////////////////////////////////////////////////////////////////

//-----------------
function XUICheckNodeName(sWhere, tNode, sName, sXSIType)
{
   var sNodeName = null;
   if (tNode != null)
      sNodeName = tNode.nodeName;

   if (sNodeName != sName)
   {
      alert(sWhere + " expecting <" + sName + ">, received <" + sNodeName + ">");
      return false;
   }
   else
   {
      if ((sXSIType != null) && (tNode.getAttribute("xsi:type") != sXSIType) && (tNode.getAttribute("type") != sXSIType))
      {
         alert(sWhere + " expecting <" + sName + " xsi:type='" + sXSIType + "'>, received xsi:type='" + tNode.getAttribute("xsi:type") + "'.");
         return false;
      }

      return true;
   }
}

function XUIGetChildItem(tParent, nPos)
{
   if ((tParent != null) && (nPos != null) && (nPos >= 0))
   {
      if (tParent.childNodes.length > nPos)
         return tParent.childNodes.item(nPos);
      else
         return tParent.lastChild;
   }
   else
      return null;
}
//-----------------
// Returns the n-th child element. If there are less than n child elements, returns null.
function XUIGetChildElement(tParent, nPos)
{
   var node = saw.getFirstChildElement(tParent);
   var n = 0;

   while (node != null)
   {
      if (node.nodeType == 1)
      {
         if (n == nPos)
            break;

         ++n;
      }

      node = saw.getNextSiblingElement(node);
   }

   return node;
}

//-----------------
function XUIGetChildPos(tParent, tChild)
{
   var i = 0;

   var t = saw.getFirstChildElement(tParent);
   while (t != null)
   {
      if (t == tChild)
         return i;

      t = saw.getNextSiblingElement(t);
      ++i;
   }

   return 0;
}

//-----------------
function XUICreateElement(tNS, sNodeName)
{
   if ((sNodeName != null) && (sNodeName.length > 0))
   {
      var tIsland = saw.getXmlIsland();
      if(tNS == null)
         return tIsland.createElement(sNodeName);

      var tElement;
      var sQualifiedName = tNS.prefix + ':' + sNodeName;
      if (is_nav)
      {
         tElement = tIsland.createElementNS(tNS.uri, tNS.prefix + ':' + sNodeName);
      }
      else
      {
         tElement = tIsland.createElement(sQualifiedName);
         saw.xml.declareNamespaceOnElement(tNS, tElement);
      }
      return tElement;
   }
   else
      return null;
}

//-----------------
function XUICreateTextNode(sNodeText)
{
   return saw.getXmlIsland().createTextNode(sNodeText);
}

//-----------------
function XUIAppendNewElement(tParent, tNS, sChild)
{
   var tChild = XUICreateElement(tNS, sChild);

   return tParent.appendChild(tChild);
}

//-----------------
function XUIInsertNewElement(tParent, tNS, sChild, nPos)
{
   var tChild = XUICreateElement(tNS, sChild);
   tParent.insertBefore(tChild, tParent.childNodes[nPos]);
   return tChild;
}

//-----------------
function XUIAssignElement(tTo, tFrom)
{
   tTo.parentNode.replaceChild(tFrom.cloneNode(true), tTo);
}

//-----------------
function XUIForceSingleNode(tParent, tNS, sNodeName)
{
   var tNode = tParent.selectSingleNode(tNS == null ? sNodeName : tNS.prefix + ':' + sNodeName);
   if (tNode == null)
      tNode = XUIAppendNewElement(tParent, tNS, sNodeName);

   return tNode;
}

//-----------------
function XUIRemoveChild(tParent, sNodeName)
{
   var tNode = tParent.selectSingleNode(sNodeName);
   if (tNode != null)
      tParent.removeChild(tNode);
}

//-----------------
function XUIRemoveAllChildren(tParent)
{
   var tNode = saw.getFirstChildElement(tParent);
   while (tNode)
   {
      var tNextNode = saw.getNextSiblingElement(tNode);
      tParent.removeChild(tNode);
      tNode = tNextNode;
   }
}

//-----------------
// This function replaces the child node if present, otherwise appends
function XUIReplaceOrAppendChild(tParent, tNewChild)
{
   var tNode = tParent.selectSingleNode(tNewChild.nodeName);
   if (tNode != null)
      tParent.replaceChild(tNewChild, tNode);
   else
      tParent.appendChild(tNewChild);
}

//-----------------
// This function removes a node if it has no children and no attributes. Returns parent if
// removed, otherwise returns null.
function XUIRemoveEmptyNode(tNode)
{
   if (tNode.attributes.length == 0 && !tNode.hasChildNodes())
   {
      var p = tNode.parentNode;
      p.removeChild(tNode);
      return p;
   }
   return null;
}

//-----------------
// This function sets the contents of the element to the text i.e. <caption>text</caption>
function XUISetElementText(tElement, sText)
{
   // if no text, then erase the text node
   if ((sText == "") || (sText == null))
   {
      if (tElement.hasChildNodes())
         tElement.removeChild(tElement.childNodes.item(0));

      return;
   }

   // otherwise, create and/or modify the text node of the caption
   if (!tElement.hasChildNodes())
   {
      var tIsland = saw.getXmlIsland();
      if (is_nav)
         tIsland = document;

      var tText = tIsland.createTextNode(sText);
      tElement.appendChild(tText);
   }
   else
      tElement.childNodes[0].nodeValue = sText;
}

//-----------------
// This function gets the contents of the element
function XUIGetElementText(tElement)
{
   // TODO: Make this compliant with C++ version of getInnerText.

   var sNodeValue = null;

   if ((tElement != null) && (tElement.firstChild))
      sNodeValue = tElement.firstChild.nodeValue;

   return (sNodeValue == null ? '' : sNodeValue);
}

//-----------------
// This function returns the xsi type without the namespace prefix
function XUIGetXsiType(tNode, sDefault)
{
   var tString = tNode.getAttribute("xsi:type");
   if (tString != null)
   {
      // remove namespace if there
      var nPos = tString.search(':');
      if (nPos >= 0)
         return tString.substr(nPos+1);
      else
         return tString;
   }
   else
      return (sDefault == null) ? "" : sDefault;
}

//-----------------
// This function returns the xsi type without the namespace prefix
function XUISetXsiType(tNode, tNS, sValue)
{
   var sQualifiedValue = tNS == null ? sValue : tNS.prefix + ':' + sValue;

   if (is_ie)
   {
      tNode.setAttribute("xsi:type", sQualifiedValue);
      saw.xml.declareNamespaceOnElement(saw.xml.kXsiNamespace, tNode);
   }
   else
      tNode.setAttributeNS(saw.xml.kXsiNamespace.uri, "xsi:type", sQualifiedValue);

   if (tNS != null)
   {
      if (is_ie)
         saw.xml.declareNamespaceOnElement(tNS, tNode);
   }
}

//-----------------
// These functions return a default of the appropriate type if the attribute is null
function XUIGetAttributeString(tNode, sAttr, sDefault)
{
   var tString = tNode.getAttribute(sAttr);

   if (tString != null)
      return tString;
   else
      return (sDefault == null) ? "" : sDefault;
}

//-----------------
function XUIGetAttributeBool(tNode, sAttr, bDefault)
{
   var tString = tNode.getAttribute(sAttr);
   if (tString != null)
      return (tString == "true");
   else
      return (bDefault == null) ? false : bDefault;
}

//-----------------
function XUISetAttributeString(tNode, sAttr, sValue)
{
   if ((sValue != null) && (sValue != ""))
      tNode.setAttribute(sAttr, sValue);
}

//-----------------
function XUISetAttributeBool(tNode, sAttr, bValue)
{
   if (bValue)
      tNode.setAttribute(sAttr, "true");
   else
      tNode.setAttribute(sAttr, "false");
}

//-----------------
// This function removes the attribute if the string is empty
function XUISetOrRemoveAttributeString(tNode, sAttr, sValue)
{
   if ((sValue != null) && (sValue != ""))
      tNode.setAttribute(sAttr, sValue);
   else
      tNode.removeAttribute(sAttr);
}

//-----------------
// This function removes the captionparent if the string is empty
function XUISetOrRemoveCaptionParent(tElement, tNS, sParentName, sValue,containsHtml)
{
   var fmt=null;
   if (containsHtml != 'undefined')
   { 
      fmt=containsHtml?'html':'text';
   }
      
   if ((sValue != null) && (sValue != ""))
   {
      var tText = new XUICaptionParent(XUIForceSingleNode(tElement, tNS, sParentName));
      tText.setCaptionText(sValue,fmt);
   }
   else
   {
      var tText = tElement.selectSingleNode(tNS.prefix + ":" + sParentName);
      if (tText != null)
         tElement.removeChild(tText);
   }
}

///////////////////////////////////////////////////////////////////////////////
// HTML UI Construction and Manipulation
///////////////////////////////////////////////////////////////////////////////

//-----------------
// This function selects an option from a <select object in a form given a
// XML element and attribute
function XUISelectOptionFromAttribute(tSelect, tNode, sAttr, sDefault)
{
   // Get the attribute value from the node defaulting to sDefault if present
   var sTarget = XUIGetAttributeString(tNode, sAttr, sDefault);

   for(var i=0; i < tSelect.options.length; ++i)
   {
      tSelect.options[i].selected = (tSelect.options[i].value == sTarget);
   }

   // If no default, choose the 0th operator
   if (sTarget == "" && tSelect.options.length > 0)
      tSelect.options[0].selected = true;
}

//-----------------
function XUISetAttributeFromSelectedOption(tSelect, tNode, sAttr)
{
   var sChoice = "";
   if (tSelect.selectedIndex >= 0)
      sChoice = tSelect.options[tSelect.selectedIndex].value;
   if ((sChoice == "default") || (sChoice == ""))
      tNode.removeAttribute(sAttr);
   else
      tNode.setAttribute(sAttr, sChoice);
}

//-----------------
function XUICreateCell(sPrefix, nNode)
{
   var tCell = document.createElement('td');
   tCell.setAttribute("name", sPrefix + nNode);

   return tCell;
}

//-----------------
function XUIAppendSelectOption(tSelect, sValue, tXMLNode, sXMLAttr, sMsg)
{
   var tOpt = document.createElement("option");

   tOpt.setAttribute("value",sValue);
   if (tXMLNode.getAttribute(sXMLAttr) == sValue)
      tOpt.selected = true;
   var tChoice = document.createTextNode(sMsg);
   tOpt.appendChild(tChoice);
   tSelect.appendChild(tOpt);

   return tOpt;
}

//-----------------
function XUICreateEditBox(sPrefix, nNode, sXMLAttr, nSize, sFunc)
{
   var tEdit = saw.createInput(sPrefix + nNode, null, "text");
   //var tEdit = document.createElement('input');
   //tEdit.name = sPrefix + nNode;
   tEdit.id = sPrefix + nNode;
   //tEdit.type="text";
   if (sFunc == null)
      tEdit.onchange = new Function("XUIOnChange" + "('" + sPrefix + "'," + nNode + ",'" + sXMLAttr + "')");
   else
      tEdit.onchange = new Function(sFunc + "(" + nNode + ")");

   if (nSize != null)
      tEdit.size = nSize;

   return tEdit;
}

//-----------------
function XUICreateCheckBox(sPrefix, nNode, sXMLAttr, sFunc)
{
   var tEdit = saw.createInput(sPrefix + nNode, null, "checkbox");
   //var tEdit = document.createElement('input');
   //tEdit.name = sPrefix + nNode;
   tEdit.id = sPrefix + nNode;
   //tEdit.type="text";
   if (sFunc == null)
      tEdit.onclick = new Function("XUIOnClick" + "('" + sPrefix + "'," + nNode + ",'" + sXMLAttr + "')");
   else
      tEdit.onclick = new Function(sFunc + "(" + nNode + ")");

   return tEdit;
}

//-----------------
function XUICreateRadio(sPrefix, nNode, sXMLAttr, sFunc)
{
   var tEdit = saw.createInput(sPrefix + nNode, null, "radio");
   //var tEdit = document.createElement('input');
   //tEdit.name = sPrefix + nNode;
   tEdit.id = sPrefix + nNode;
   //tEdit.type="text";
   if (sFunc == null)
      tRad.onclick = new Function("XUIOnClick" + "('" + sPrefix + "'," + nNode + ",'" + sXMLAttr + "')");
   else
      tRad.onclick = new Function(sFunc + "(" + nNode + ")");

   return tRad;
}

//-----------------
function XUICreateTextArea(sPrefix, nNode, sXMLAttr, nRows, nCols)
{
   var tEdit = document.createElement('textarea');
   tEdit.name= sPrefix + nNode;
   tEdit.id = sPrefix + nNode;
   if (nRows != null)
      tEdit.rows = nRows;
   if (nCols != null)
      tEdit.cols = nCols;
   tEdit.onchange = new Function("XUIOnChange" + "('" + sPrefix + "'," + nNode + ",'" + sXMLAttr + "')");

   return tEdit;
}

//-----------------
function XUICreateDropDown(sPrefix, nNode, sXMLAttr, sFunc)
{
   var tDrop = document.createElement('select');
   tDrop.name = sPrefix + nNode;
   tDrop.id = sPrefix + nNode;
   if (sFunc == null)
      tDrop.onchange = new Function("XUIOnChoose" + "('" + sPrefix + "'," + nNode + ",'" + sXMLAttr + "')");
   else
      tDrop.onchange = new Function(sFunc + "(" + nNode + ")");

   return tDrop;
}

//-----------------
// n = XML node index
function XUIDelete(sTableID, n)
{
   var tElement = XUIGetViewXML();

   if (n < 0)
      return;

   if (n >= tElement.childNodes.length)
      return;

   tElement.removeChild(tElement.childNodes.item(n));
}

//-----------------
// n = XML node index
function XUIMoveUp(sTableID, n)
{
   var tElement = XUIGetViewXML();

   if (n < 1)
      return;

   if (n >= tElement.childNodes.length)
      return;

   tElement.insertBefore(tElement.childNodes.item(n), tElement.childNodes.item(n-1));
}

//-----------------
// n = XML node index
function XUIMoveDown(sTableID, n)
{
   var tElement = XUIGetViewXML();

   if (n < 0)
      return;

   if (n >= tElement.childNodes.length - 1)
      return;

   tElement.insertBefore(tElement.childNodes.item(n+1), tElement.childNodes.item(n));
}

//-----------------
// n = XML node index
function XUIGetChildNode(nID)
{
   var tElement = XUIGetViewXML();
   return tElement.childNodes.item(nID);
}

//-----------------
function XUIOnChoose(sPrefix, nID, sAttr)
{
   var tCtl = document.getElementById(sPrefix + nID);
   var tPrompt = XUIGetChildNode(nID);
   if (tCtl != null)
   {
      var sOp = tCtl.options[tCtl.selectedIndex].value;
      tPrompt.setAttribute(sAttr,sOp);
   }

   return tPrompt;
}

//-----------------
function XUIOnChange(sPrefix, nID, sAttr)
{
   var tCtl = document.getElementById(sPrefix + nID);
   var tPrompt = XUIGetChildNode(nID);
   if (tCtl != null)
      tPrompt.setAttribute(sAttr,tCtl.value);

   return tPrompt;
}

//-----------------
function XUIOnClick(sPrefix, nID, sAttr)
{
   var tCtl = document.getElementById(sPrefix + nID);
   var tPrompt = XUIGetChildNode(nID);
   if (tCtl != null)
      tPrompt.setAttribute(sAttr,tCtl.checked ? "true" : "false");

   return tPrompt;
}

//-----------------
function XUIIsChecked(sPrefix, nID)
{
   var tCtl = document.getElementById(sPrefix + nID);
   if (tCtl != null)
      return tCtl.checked;
   else
      return false;
}

//-----------------
function XUISetChecked(sPrefix, nID, bChecked)
{
   var tCtl = document.getElementById(sPrefix + nID);
   if (tCtl != null)
      tCtl.checked = bChecked;
}

//-----------------
// sFunction is an optional function of the form Handler(sTable, nNode) to call
// otherwise XUIDelete is called
function XUICreateDeleteLink(sTableID, nNode, sFunction)
{
   var tImg = document.createElement("IMG");
   tImg.border = 0;
   tImg.src = WebScriptMapGet("Common/opDelete.gif");

   var tLink = document.createElement("A");

   var sHREF = "javascript:";
   if (sFunction == null)
      sHREF += "XUIDelete";
   else
      sHREF += sFunction;
   sHREF += "('" + sTableID + "',";
   sHREF += nNode + ")";

   tLink.href = sHREF;

   tLink.appendChild(tImg);

   return tLink;
}

//-----------------
// sFunction is an optional function of the form Handler(sTable, nNode) to call
// otherwise XUIMoveUp is called
function XUICreateMoveUpLink(sTableID, nNode, sFunction)
{
   var tImg = document.createElement("IMG");
   tImg.border = 0;
   tImg.src = WebScriptMapGet("Common/opUp.gif");

   var tLink = document.createElement("A");

   var sHREF = "javascript:";
   if (sFunction == null)
      sHREF += "XUIMoveUp";
   else
      sHREF += sFunction;
   sHREF += "('" + sTableID + "',";
   sHREF += nNode + ")";

   tLink.href = sHREF;

   tLink.appendChild(tImg);

   return tLink;
}

//-----------------
// sFunction is an optional function of the form Handler(sTable, nNode) to call
// otherwise XUIMoveDown is called
function XUICreateMoveDownLink(sTableID, nNode, sFunction)
{
   var tImg = document.createElement("IMG");
   tImg.border = 0;
   tImg.src = WebScriptMapGet("Common/opDown.gif");

   var tLink = document.createElement("A");

   var sHREF = "javascript:";
   if (sFunction == null)
      sHREF += "XUIMoveDown";
   else
      sHREF += sFunction;
   sHREF += "('" + sTableID + "',";
   sHREF += nNode + ")";

   tLink.href = sHREF;

   tLink.appendChild(tImg);

   return tLink;
}

//-----------------
// sFunction is an optional function of the form Handler(sTable, nNode)
function XUICreateHyperLink(sTableID, nNode, sMsg, sFunction)
{
   var tLink = document.createElement("A");

   var sHREF = "javascript:";
   sHREF += sFunction;
   sHREF += "('" + sTableID + "',";
   sHREF += nNode + ")";

   tLink.href = sHREF;

   var tMsg = document.createTextNode(sMsg);
   tLink.appendChild(tMsg);

   return tLink;
}

function XUICriteria(tNode)
{
   this.element = tNode;
}

XUICriteria.removeColumnWithID = function(tCriteriaElement, sColumnID)
{
   if ((tCriteriaElement == null) || (sColumnID == null) || (sColumnID == ""))
      return;


   var tColumn = tCriteriaElement.selectSingleNode("saw:columns/saw:column[@columnID='" + sColumnID + "']");

   if(tColumn != null)
   {
      tColumn.parentNode.removeChild(tColumn);
   }

   var tOrderBy = tCriteriaElement.selectSingleNode("saw:columnOrder/saw:columnRef[@columnID='" + sColumnID + "']");

   if(tOrderBy != null)
   {
      tOrderBy.parentNode.removeChild(tOrderBy);
   }
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Column Access for an <saw:column> element
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

function XUIColumn(tNode)
{
   this.element = tNode;
}

//-----------------
XUIColumn.prototype.getFormula = function()
{
   return this.element.getAttribute('formula');
}

//-----------------
XUIColumn.getColumnHeadingFromFormula = function(sFormula)
{
   if (sFormula != null)
   {
      // Remove quotes from quoted text
      var re = /"([^"]*)"/g;
      sFormula = sFormula.replace(re, "$1");
      
      if (XUIColumn.hasWebVariableExpressions(sFormula))
         return sFormula;

      var nDot = sFormula.lastIndexOf('.');
      if (nDot >= 0)
         return sFormula.substring(nDot+1);
      else
         return sFormula;
   }

   return "";
}

XUIColumn.hasCustomHeadings = function(tColumn)
{
   if (null == tColumn)
      return false;

   var tTableHeading = tColumn.selectSingleNode('saw:tableHeading');
   if (null != tTableHeading)
   {
      var tTblHdgCaption = tTableHeading.selectSingleNode('saw:caption');
      if (null != tTblHdgCaption)
         return true;
   }

   var tColumnHeading = tColumn.selectSingleNode('saw:columnHeading');
   if (null != tColumnHeading)
   {
      var tColHdgCaption = tColumnHeading.selectSingleNode('saw:caption');
      if (null != tColHdgCaption)
         return true;
   }

   return false;
}

//-----------------
XUIColumn.getTableHeadingFromFormula = function(sFormula)
{
   if (sFormula != null)
   {
      // Remove quotes from quoted text
      var re = /"([^"]*)"/g;
      sFormula = sFormula.replace(re, "$1");
      
      if (XUIColumn.hasWebVariableExpressions(sFormula))
         return "";

      var nDot = sFormula.indexOf('.');
      if (nDot >= 0)
         return sFormula.substring(0, nDot);
   }
   return "";
}

//-----------------
XUIColumn.hasWebVariableExpressions = function(sFormula)
{
   if (sFormula != null)
   {
      var iIndex = sFormula.indexOf("@{");
      if (iIndex != -1)
      {
         // @ might be escaped
         if (iIndex == 0 ||
             sFormula.charAt(iIndex - 1) != '\\')
            return true;
      }
   }
   
   return false;
}

//-----------------
// Returns null if the formula doesn't require a special heading
XUIColumn.getSpecialHeadingFromFormula = function(sFormula, nMax)
{
   if (sFormula != null)
   {
      nMax = nMax == null ? 35 : nMax;

      // Remove quotes from quoted text
      var re = /"([^"]*)"/g;
      sFormula = sFormula.replace(re, "$1");
      
      // check for web variable expressions
      if (XUIColumn.hasWebVariableExpressions(sFormula))
      {
         var sResult = sFormula;
         sResult = (sResult.length > nMax) ? sResult.substr(0, nMax-3) + "..." : sResult;
         return sResult;
      }

      // Check for a case statement
      var caseRe = /CASE.+END/gi;
      var nCase = sFormula.search(caseRe);
      if (nCase >= 0)
      {
         var sResult = sFormula.substring(nCase+5);
         sResult = (sResult.length > nMax) ? sResult.substr(0, nMax-3) + "..." : sResult;
         return "Case " + sResult;
      }

      // Check for a function syntax: aggrule(formula) aggrule should not contain a '.'
      var castRe = /^\s*\w+\s*\(.+\)\s*$/gi;
      var nCast = sFormula.search(castRe);
      if (nCast >= 0)
      {
         var sResult = sFormula;
         sResult = (sResult.length > nMax) ? sResult.substr(0, nMax-3) + "..." : sResult;
         return sResult;
      }
   }

   return null;
}

//-----------------
XUIColumn.getDisplayHeadingFromFormula = function(sFormula, nMax)
{
   var sResult = XUIColumn.getSpecialHeadingFromFormula(sFormula, nMax);
   if (sResult == null)
   {
      nMax = nMax == null ? 35 : nMax;

      var nDot = sFormula.lastIndexOf('.');
      if (nDot >= 0)
         sResult = sFormula.substring(nDot+1);
      else
         sResult = sFormula;
      var re = /"([^"]*)"/g;
      sResult = sResult.replace(re, "$1");

      return (sResult.length > nMax) ? sResult.substr(0, nMax-3) + "..." : sResult;
   }
   else
      return sResult;
}

///////////////////////////////////////////////////////////////////////////////
// Column Space Access
///////////////////////////////////////////////////////////////////////////////

//-----------------
// This function populates and returns the static column space element from the
// XML island

function XUIColumnSpace(csNode)
{
   if (csNode == null)
   {
      var tNQW = XUIGetRootXML();//document.getElementById("idXUI");

      XUIColumnSpace.xmlElement = tNQW ? tNQW.selectSingleNode('saw:columnSpace') : null;
      if(XUIColumnSpace.xmlElement == null) // shouldn't happen
      {
         //alert('No Column Space XML found in Document');

         XUIColumnSpace.xmlElement = XUICreateElement(saw.xml.kSawNamespace, "columnSpace");
      }
   }
   else if (csNode.nodeName == 'saw:columnSpace')
      XUIColumnSpace.xmlElement = csNode;
   else
      alert('Invalid XML passed to XUIColumnSpace constructor.'); // programming logic error

   return XUIColumnSpace.xmlElement;
}

//-----------------
XUIColumnSpace.setColumnSpaceElement = function(csNode)
{
   if (csNode.nodeName != 'saw:columnSpace')
   {
      // No need to localize? This is a logic error
      alert('Invalid XML passed to XUIColumnSpace.setColumnSpaceElement.');
      return;
   }

   XUIColumnSpace.xmlElement = csNode;
}

//-----------------
XUIColumnSpace.getColumnSpaceElement = function()
{
   return XUIColumnSpace.xmlElement;
}

//-----------------
// Add columns to columnspace
XUIColumnSpace.addColumnsFromColumnSpace = function(tNewColumnSpaceNode)
{
   if (!tNewColumnSpaceNode)
      return;
   var vColumns = tNewColumnSpaceNode.selectNodes('saw:columnInfo');
   for (var i=0; i<vColumns.length; i++)
      XUIColumnSpace.addColumnInfoFromNode(vColumns[i]);
}

XUIColumnSpace.addColumnInfoFromNode = function(tNewColumnNode)
{
   var sColumnID = tNewColumnNode.getAttribute("columnID");
   var sFormula = tNewColumnNode.getAttribute("formula");

   if (!XUIColumnSpace.findInfo(sColumnID, sFormula))
      XUIColumnSpace.xmlElement.appendChild(tNewColumnNode);

}


//-----------------
// DEPRECATED
function XUIGetColumnSpace()
{
   return XUIColumnSpace.getColumnSpaceElement();
}

//-----------------
XUIColumnSpace.getInfoFormatAttr = function(tNode, sAttr)
{
   if (!XUICheckNodeName("XUIColumnSpace.getInfoFormatAttr", tNode, "saw:columnInfo"))
      return null;

   var tColumn = tNode.selectSingleNode("saw:column");
   if (tColumn != null)
   {
      var tFormat = tNode.selectSingleNode("saw:displayFormat");
      if (tFormat != null)
         return tFormat.getAttribute(sAttr);
   }

   return null;
}

//-----------------
// tNode must be a columnInfo node or something with an columnID attribute
XUIColumnSpace.getInfoHeading = function(tNode, sName, nMax)
{
   if (tNode == null)
      return "";

   if (tNode.nodeName != "saw:columnInfo")
      tNode = XUIColumnSpace.findInfo(XUIGetAttributeString(tNode, "columnID", "missing"));

   if (tNode != null)
   {
      var tColumn = tNode.selectSingleNode("saw:column");

      if (tColumn != null)
      {
         if (sName == "saw:columnHeading")
         {
            var sFormula = tColumn.getAttribute("formula");
            // is there a columnExpr present?
            {
               var sColumnExpr = XUIGetAttributeString(tColumn, "columnExpr");
               if (XUIColumn.hasWebVariableExpressions(sColumnExpr))
                  sFormula = sColumnExpr;
            }
            
            var sSpecial = XUIColumn.getSpecialHeadingFromFormula(sFormula, nMax);
            if (sSpecial != null)
               return sSpecial;
         }

         var tHdg = new XUICaptionParent(tColumn.selectSingleNode(sName));
         return tHdg.getCaptionText();
      }
   }

   return "";
}

//-----------------
// This function returns the heading from the column or the column space.  It
// checks the customHedings flag and builds from the formula
XUIColumnSpace.getHeadingFromColumn = function(tColumn, sName)
{
   if (XUICheckNodeName("XUIColumnSpace.getHeadingFromColumn", tColumn, "saw:column"))
   {
      if (XUIColumn.hasCustomHeadings(tColumn))
      {
         return XUICaptionSpace.getCaptionText(tColumn.selectSingleNode(sName));
      }
      else
      {
         var sFormula = tColumn.getAttribute("formula");
         var tInfo = XUIColumnSpace.findInfo(tColumn.getAttribute("columnID"), sFormula);
         if (tInfo == null)
         {
            if (sName == "saw:tableHeading")
               return XUIColumn.getTableHeadingFromFormula(sFormula);
            else
               return XUIColumn.getColumnHeadingFromFormula(sFormula);
         }
         else
         {
            return XUIColumnSpace.getInfoHeading(tInfo, sName);
         }
      }
   }

   return "";
}

//-----------------
// This function returns the heading from the column or the column space
XUIColumnSpace.getTableHeadingFromColumn = function(tColumn)
{
   return XUIColumnSpace.getHeadingFromColumn(tColumn, "saw:tableHeading");
}

//-----------------
// This function returns the heading from the column or the column space
XUIColumnSpace.getColumnHeadingFromColumn = function(tColumn)
{
   return XUIColumnSpace.getHeadingFromColumn(tColumn, "saw:columnHeading");
}

//-----------------
// This function returns the heading from the report column or the column space
// tNode must have an columnID or unknown is returned
XUIColumnSpace.getHeadingFromColumnID = function(tReport, sColumnID, sName)
{
   XUICheckNodeName("XUIColumnSpace.getHeadingFromColumnID", tReport, "saw:report");

   if (sColumnID != null)
   {
      var tRptCol = tReport.selectSingleNode("//saw:column[@columnID='" + sColumnID + "']");
      if (tRptCol != null)
         return XUIColumnSpace.getHeadingFromColumn(tRptCol, sName);
   }

   return "";
}

//-----------------
// tNode must be a columnInfo node or something with an columnID attribute
XUIColumnSpace.getInfoSQLAttr = function(tNode, sAttr)
{
   if (tNode.nodeName != "saw:columnInfo")
      tNode = XUIColumnSpace.findInfo(tNode.getAttribute("columnID"));

   if (tNode != null)
   {
      var tsi = tNode.selectSingleNode("saw:SQLInfo");
      if (tsi != null)
         return tsi.getAttribute(sAttr);
   }

   return null;
}

//-----------------
XUIColumnSpace.findInfo = function(sColumnID, sFormula)
{
   if (sColumnID == null)
   {
      var tReturn = XUIColumnSpace.xmlElement.selectSingleNode("saw:columnInfo[@formula=" + saw.createXPathStringLiteral(sFormula) + "]");
      // the columnExpr attribute will have the 'unresolved' formula (prior to web variable expression evaluation)
      if (null == tReturn)
         tReturn = XUIColumnSpace.xmlElement.selectSingleNode("saw:columnInfo[@columnExpr=" + saw.createXPathStringLiteral(sFormula) + "]");
      return tReturn;
   }
   else if (sFormula == null)
      return XUIColumnSpace.xmlElement.selectSingleNode("saw:columnInfo[@columnID='" + sColumnID + "']");
   else
   {
      var tReturn = XUIColumnSpace.xmlElement.selectSingleNode("saw:columnInfo[@columnID='" + sColumnID + "' and @formula=" + saw.createXPathStringLiteral(sFormula) + "]");
      // the columnExpr attribute will have the 'unresolved' formula (prior to web variable expression evaluation)
      if (null == tReturn)
         tReturn = XUIColumnSpace.xmlElement.selectSingleNode("saw:columnInfo[@columnID='" + sColumnID + "' and @columnExpr=" + saw.createXPathStringLiteral(sFormula) + "]");
      return tReturn;
   }
}

//-----------------
XUIColumnSpace.addColumnInfo = function(tColumnDef, sColumnID)
{
   var tNew = XUIAppendNewElement(XUIColumnSpace.xmlElement, saw.xml.kSawNamespace, "columnInfo");
   if (saw.checkObjectReference(sColumnID))
      tNew.setAttribute("columnID", sColumnID);
   XUISetAttributeString(tNew, "columnExpr", tColumnDef.GetSQLFormula());
   XUISetAttributeString(tNew, "formula", tColumnDef.GetSQLFormula());
   if (tColumnDef.GetSubjectArea() && tColumnDef.GetSubjectArea().sSubjectAreaSQL  && tColumnDef.GetSubjectArea().sSubjectAreaSQL != "")
      XUISetAttributeString(tNew, "subjectArea", tColumnDef.GetSubjectArea().sSubjectAreaSQL);
   
   var tInfo = XUIAppendNewElement(tNew, saw.xml.kSawNamespace, "SQLInfo");
   XUISetAttributeString(tInfo, "aggType", tColumnDef.GetAggregateType());
   XUISetAttributeString(tInfo, "aggRule", tColumnDef.GetAggregationRule());
   XUISetAttributeString(tInfo, "primaryType", tColumnDef.GetPrimaryType());
   XUISetAttributeString(tInfo, "category", tColumnDef.GetCategory());
   
   if (tColumnDef.GetPrimaryType() == 'timeStamp')
   {
      XUISetAttributeString(tInfo, "timeZone", tColumnDef.GetDataTZOffset());
      tNew.setAttribute("displayDefaultTZ", tColumnDef.GetDisplayTZ());
      tNew.setAttribute("displayDefaultTZOffset", tColumnDef.GetDisplayTZOffset());
   }

   var tColumn = XUIAppendNewElement(tNew, saw.xml.kSawNamespace, "column");
   XUISetAttributeString(tColumn, "formula", tColumnDef.GetSQLFormula());

   var tHdg = XUIAppendNewElement(tColumn, saw.xml.kSawNamespace, 'tableHeading');
   var tCap = new XUICaptionParent(tHdg);
   tCap.setCaptionText(tColumnDef.GetTableHeading());

   var tHdg = XUIAppendNewElement(tColumn, saw.xml.kSawNamespace, 'columnHeading');
   var tCap = new XUICaptionParent(tHdg);
   tCap.setCaptionText(tColumnDef.GetColumnHeading());

   return tNew;
}

//-----------------
XUIColumnSpace.replaceColumnInfo = function(tColInfo)
{
   if (tColInfo != null)
   {
      var tCurrent = XUIColumnSpace.findInfo(tColInfo.getAttribute("columnID"));
      if (tCurrent != null)
      {
         return XUIColumnSpace.xmlElement.replaceChild(tColInfo, tCurrent);
      }
   }
   return null;
}

///////////////////////////////////////////////////////////////////////////////
// Caption Space Access
///////////////////////////////////////////////////////////////////////////////
// The captionSpace contains externalized captions referenced in the report
// XML

//-----------------
// This function populates and returns the static caption space element from the
// XML island
function XUICaptionSpace()
{
   var tNQW = XUIGetRootXML();
   XUICaptionSpace.xmlElement = tNQW ? tNQW.selectSingleNode('saw:captionSpace') : null;

   if(XUICaptionSpace.xmlElement == null) // shouldn't happen
   {
      //alert('No Caption Space XML found in Document');

      XUICaptionSpace.xmlElement = XUICreateElement(saw.xml.kSawNamespace,"captionSpace");
   }

   return XUICaptionSpace.xmlElement;
}

//-----------------
XUICaptionSpace.getCaptionText = function(tParentNode)
{
   // tNode can be any element containing a caption
   var tCapParent = new XUICaptionParent(tParentNode);
   var tCap = XUICaptionSpace.findExternalCaption(tCapParent.getCaptionID());
   if (tCap != null)
      return XUICaptionSpace.getTextFromCaption(tCap);
   else
      return tCapParent.getCaptionText();
}

//-----------------
XUICaptionSpace.findExternalCaption = function(sCaptionID)
{
   if (sCaptionID != null && XUICaptionSpace.xmlElement)
      return XUICaptionSpace.xmlElement.selectSingleNode('saw:caption[@captionID="' + sCaptionID + '"]');
   else
      return null;
}

//-----------------
// Static function the pulls the text from the text node within a caption
XUICaptionSpace.getTextFromCaption = function(tCaptionNode)
{
   return XUIGetElementText(tCaptionNode);
}

//-----------------
// Add captions to captionspace
XUICaptionSpace.addCaptions = function(tNewCaptionSpaceNode)
{
   if (!tNewCaptionSpaceNode)
      return;
   var vCaptions = tNewCaptionSpaceNode.selectNodes('saw:caption');
   for (var i=0; i<vCaptions.length; i++)
      XUICaptionSpace.addCaption(vCaptions[i]);
}

XUICaptionSpace.addCaption = function(tNewCaptionNode)
{
   var sCaptionID = tNewCaptionNode.getAttribute("captionID");

   if (!XUICaptionSpace.xmlElement.selectSingleNode('saw:caption[@captionID="' + sCaptionID + '"]'))
      XUICaptionSpace.xmlElement.appendChild(tNewCaptionNode);

}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Caption Parent Wrapper
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

//-----------------
// This wrapper function manages a caption node under a parent node
function XUICaptionParent(tParentNode)
{
   this.element = tParentNode;
}

//-----------------
XUICaptionParent.prototype.getCaptionText = function()
{
   if (this.element != null)
   {
      var tText = this.element.selectSingleNode("saw:caption/saw:text");
      if (tText != null)
      {
         return XUIGetElementText(tText);
      }
   }
   return "";
}

//-----------------
XUICaptionParent.prototype.removeCaption = function()
{
   if (this.element == null)
      return;

   var tCaption = this.element.selectSingleNode("saw:caption");
   if (tCaption != null)
      this.element.removeChild(tCaption);
}

//-----------------
XUICaptionParent.prototype.setCaptionText = function(sCaption,fmt)
{
   if (this.element == null)
      return false;
   

   if ((sCaption == null) || (sCaption.length == 0))
   {
      this.removeCaption();
      return false;
   }

   var tCaption = XUIForceSingleNode(this.element, saw.xml.kSawNamespace, "caption");
   if (fmt != 'undefined' && fmt != null)
      tCaption.setAttribute("fmt", fmt);

   // if the caption was externalized, save the old ID so the externalziation program can use it.
   if (this.isReference())
   {
      if (this.getCaptionText() == sCaption)
         return;
      tCaption.setAttribute("oldID", tCaption.getAttribute("captionID"));
      tCaption.removeAttribute("captionID");
   }

   var tText = XUIForceSingleNode(tCaption, saw.xml.kSawNamespace, "text");
   XUISetElementText(tText, sCaption);
   return true;
}

//-----------------
XUICaptionParent.prototype.isReference = function()
{
   return (this.getCaptionID() != null);
}

//-----------------
XUICaptionParent.prototype.getCaptionID = function()
{
   if (this.element != null)
   {
      var tCaption = this.element.selectSingleNode("saw:caption");
      if (tCaption != null)
      { 
         var tAttr = tCaption.getAttribute("captionID");
         if (tAttr == null)
         {
            tAttr = tCaption.getAttribute("captionId");
         }
         return tAttr;
      } 
   }

   return null;
}

//-----------------
XUICaptionParent.prototype.getOldCaptionID = function()
{
   if (this.element != null)
   {
      var tCaption = this.element.selectSingleNode("saw:caption");
      if (tCaption != null)
      {
         var tAttr = tCaption.getAttribute("oldID");
         if (tAttr == null)
         { 
            tAttr =  tCaption.getAttribute("oldId");
         }
         return tAttr;
      } 
   }

   return null;
}

///////////////////////////////////////////////////////////////////////////////
// Catalog Caption Space Access
///////////////////////////////////////////////////////////////////////////////
// The catalogCaptionSpace contains externalized captions for the items in
// catalog object paths

//-----------------
// This function populates and returns the static catalog caption space element from the
// XML island
function XUICatalogCaptionSpace()
{
   var tNQW = XUIGetRootXML();
   XUICatalogCaptionSpace.xmlElement = tNQW ? tNQW.selectSingleNode('saw:catalogCaptionSpace') : null;

   if(XUICatalogCaptionSpace.xmlElement == null) // shouldn't happen
   {
      //alert('No Catalog Caption Space XML found in Document');

      XUICatalogCaptionSpace.xmlElement = XUICreateElement(saw.xml.kSawNamespace,"catalogCaptionSpace");
   }

   return XUICatalogCaptionSpace.xmlElement;
}

//-----------------
XUICatalogCaptionSpace.getFolderCaption = function(sPath)
{
   if (null == sPath ||
       sPath == "")
      return "";

   var sExternalFolderCaption = XUICatalogCaptionSpace.findExternalCaption(sPath, false);
   if (sExternalFolderCaption != null)
      return sExternalFolderCaption;

   return saw.getFolder(sPath);
}

//-----------------
XUICatalogCaptionSpace.getLocalizedCaption = function(sPath)
{
   if (null == sPath ||
       sPath == "")
      return "";

   var sExternalItemNameCaption = XUICatalogCaptionSpace.findExternalCaption(sPath, true);
   if (sExternalItemNameCaption != null)
      return sExternalItemNameCaption;

   // RIE: this should returned a displayable itemname.
   return saw.getItemName(sPath);
}

//-----------------
XUICatalogCaptionSpace.getPathCaption = function(sPath)
{
   if (null == sPath ||
       sPath == "")
      return "";

   var sExternalPath = XUICatalogCaptionSpace.getFolderCaption(sPath);
   sExternalPath += "/" + XUICatalogCaptionSpace.getLocalizedCaption(sPath);

   return sExternalPath;
}

//-----------------
XUICatalogCaptionSpace.findExternalCaption = function(sPath, bGetItemName)
{
   if (null == bGetItemName)
      bGetItemName = true;

   if (XUICaptionSpace.xmlElement)
   {
      var sXPathAttr = saw.createXPathStringLiteral(sPath);
      var tCatalogPathCaptions = XUICatalogCaptionSpace().selectSingleNode('saw:catalogPathCaptions[@path=' + sXPathAttr + ']');
      if (null != tCatalogPathCaptions)
      {
         if (bGetItemName)
            return XUIGetElementText(tCatalogPathCaptions.firstChild);
         else
         {
            var sExternalFolderCaption = "";
            var tItemNameElement = tCatalogPathCaptions.lastChild;
            while (null != tItemNameElement &&
                   tItemNameElement != tCatalogPathCaptions.firstChild)
            {
               sExternalFolderCaption += "/";
               sExternalFolderCaption += XUIGetElementText(tItemNameElement);

               tItemNameElement = tItemNameElement.previousSibling;
            }

            if (sExternalFolderCaption != "")
               return sExternalFolderCaption;
         }
      }
   }

   return null;
}

XUICatalogCaptionSpace.add = function(xmlElement)
{
   if (xmlElement)
   {
      if(XUICatalogCaptionSpace.xmlElement && xmlElement.nodeName == 'saw:catalogCaptionSpace')
      {
         // loop through the children of the passed xmlElement and try add them to the space.
         var tNode = xmlElement.firstChild;
         while(tNode)
         {
            var tSpaceNode = null;
            tSpaceNode = XUICatalogCaptionSpace.xmlElement.selectSingleNode('saw:catalogPathCaptions[@path=' + saw.createXPathStringLiteral(XUIGetAttributeString(tNode,"path")) + ']');

            if(tSpaceNode == null)
            {
               XUICatalogCaptionSpace.xmlElement.appendChild(tNode);
               //alert(XUICatalogCaptionSpace.xmlElement.xml);
            }

            tNode = tNode.nextSibling;
         }
      }
   }
}



///////////////////////////////////////////////////////////////////////////////
// XUIEditor Base Class
///////////////////////////////////////////////////////////////////////////////

//-----------------
function XUIEditor()
{
}

//-----------------
// Child panel was applied, so generate an onChange event for this editor.  onChildApply
// does not propogate to parents

XUIEditor.prototype.onChildApply = function(sourceEditor) // virtual
{
   this.panel.onChange(this);
}

XUIEditor.prototype.onChange = function(sourceEditor) // virtual
{
   // do nothing

   return true; // continue notfication, return false to stop propagation to parent editors
}

//-----------------
// Fired when editor becomes visible on screen (currently only for popup dialogs)
XUIEditor.prototype.onDisplay = function() // virtual
{
   // do nothing
}

//-----------------
// Fired whenever editor is moved
XUIEditor.prototype.onMove = function(left,top) // virtual
{
   // do nothing
}

// xmlElement is the element you're editing.  refElement is an optional element that contains
// context (i.e. the report in which the view xmlElement lives)
// CAUTION: If your using both, set the xmlelement and refelement into something other than
// this.element
XUIEditor.prototype.load = function(xmlElement, refElement) // virtual
{
   // OVERRIDE THIS METHOD
}

XUIEditor.prototype.refresh = function(editor) // virtual
{
   // override to reload the specified child editor
}

XUIEditor.prototype.apply = function() // virtual
{
   // OVERRIDE THIS METHOD

   return false;
}

XUIEditor.prototype.discard = function(event)
{
   // do nothing
}

XUIEditor.prototype.focus = function()
{
   // do nothing
}

XUIEditor.prototype.handleCaretStore = function(tTextElement)
{
   // do nothing
}

function onEditorStoreCaret(sID,tTextElement)
{
    var tEditor = XUIPanel.getEditor(sID);
    if (tEditor && tEditor.handleCaretStore)
        tEditor.handleCaretStore(tTextElement);
}

///////////////////////////////////////////////////////////////////////////////
// Caption Editor
///////////////////////////////////////////////////////////////////////////////

function CaptionEditor(editorID)
{
   this.form = document.forms[editorID + 'Form'];
   this.eid = editorID;
}

CaptionEditor.prototype = new XUIEditor();

//-----------------
CaptionEditor.prototype.load = function(xmlElement)
{
   this.element = xmlElement;

   this.form.caption.value = XUICaptionSpace.getCaptionText(xmlElement);
}

//-----------------
CaptionEditor.prototype.apply = function()
{
   var tCaptionParent = new XUICaptionParent(this.element);
   if (this.form.caption.value == "")
      tCaptionParent.removeCaption();
   else
   {
      tCaptionParent.setCaptionText(this.form.caption.value);
   }

   return true;
}

//-----------------
CaptionEditor.prototype.focus = function()
{
   this.form.caption.focus();
}

///////////////////////////////////////////////////////////////////////////////
// Debug Editor
///////////////////////////////////////////////////////////////////////////////

//-----------------
function XUIDebugger(editorID)
{
   this.textArea = document.getElementById(editorID + 'TextArea');

   if (this.textArea == null)
      alert('You need to include kuiDebugger on your page');
}

XUIDebugger.prototype = new XUIEditor();

//-----------------
XUIDebugger.formatNode = function(sXML, tCursor, nDepth)
{
   var ksTab = "   ";

   var kTerminalTag = 1; // <.../>*
   var kInBeginTag = 2; // <...*....>
   var kEndingBeginTag = 3;  // <... /*>
   var kBeginningNewTag = 4; // ...<*
   var kInNode = 5; // <...>...*...</...>
   var kEndTag = 6; // </*...>

   var c;
   var sResult = "";

   while (tCursor.pos < sXML.length)
   {
      c = sXML.charAt(tCursor.pos);
      if (c == "\r" || c == "\n")
      {
         tCursor.pos++;
         continue;
      }

      if (tCursor.state == kInBeginTag)
      {
         if (c == "/")
            tCursor.state = kEndingBeginTag;

         else if (c == ">")
            tCursor.state = kInNode;
      }
      else if (tCursor.state == kEndingBeginTag)
      {
         if (c == ">")
         {
            // this was a /> tag
            tCursor.state = kInNode;
            return sResult + c;
         }
         else
            tCursor.state = kInBeginTag;
      }
      else if ((tCursor.state == kInNode) || (typeof(tCursor.state) == "undefined"))
      {
         if (c == "<")
         {
            tCursor.state = kBeginningNewTag;

            //alert ("Before[" + nDepth + "] " + sResult);

            var s = XUIDebugger.formatNode(sXML, tCursor, nDepth+1);
            c = "";

            //alert ("Return[" + nDepth + "] " + s);

            if (tCursor.state == kEndTag)
            {
               //sResult += "\r\n[b1-" + nDepth + "]";
               //sResult += "\r\n";
               //for (var i = 0; i < nDepth-1; i++)
               // sResult += ksTab;

               //sResult += s + "[a1]\r\n";
               sResult += s;

               tCursor.state = kInNode;
               return sResult;
            }
            else if (tCursor.state == kInNode)
            {
               //sResult += "\r\n[b2-" + nDepth + "]";
               sResult += "\r\n";
               for (var i = 0; i < nDepth; i++)
                  sResult += ksTab;

               //sResult += s + "[a2]\r\n";
               sResult += s;
            }
            else
               sResult += s;
         }
      }
      else if (tCursor.state == kBeginningNewTag)
      {
         if (c == "/")
            tCursor.state = kEndTag;
         else if (c != "<")
            tCursor.state = kInBeginTag;
      }
      else if (tCursor.state == kEndTag)
      {
         if (c == ">")
            return sResult + c;
      }
      else // invalid state
      {
         alert ('Invalid State' + sXML.substring(tCursor.pos, 10000));
      }

      sResult += c;
      tCursor.pos++;
   }

   return sResult;
}

//-----------------
XUIDebugger.prototype.load = function(xmlElement)
{
   this.element = xmlElement;
   this.textArea.value = saw.getXmlText(xmlElement);
}

//-----------------
XUIDebugger.prototype.apply = function()
{
   var tIsland = saw.getXmlIsland("idDebugger");
   if (!tIsland.loadXML(this.textArea.value))
   {
      alert('Parse Error');
      return false;
   }
   else
   {
      // allow temporary override of caption and column space
      if (saw.getFirstChildElement(tIsland).nodeName == "saw:columnSpace")
         XUIColumnSpace.xmlElement = saw.getFirstChildElement(tIsland);
      else if (saw.getFirstChildElement(tIsland).nodeName == "saw:captionSpace")
         XUICaptionSpace.xmlElement = saw.getFirstChildElement(tIsland);
      else // report
      {
         // verify same node name
         if (this.element.nodeName != saw.getFirstChildElement(tIsland).nodeName)
         {
            alert('Cannot change element from ' + this.element.nodeName + ' to ' + saw.getFirstChildElement(tIsland).nodeName);
            return false;
         }

         XUIAssignElement(this.element, saw.getFirstChildElement(tIsland));

         //tParent.replaceChild(tIsland.firstChild, this.element);
         this.element = null; // needs to be reset by parent editor
      }

      return true;
   }
}

//-----------------
XUIDebugger.onSetXML = function(eid)
{
   var tPanel = XUIPanel.getPanel(eid);
   tPanel.apply();
}

//-----------------
XUIDebugger.onGetXML = function(eid, event)
{
   var tEd = XUIPanel.getEditor(eid);
   tEd.parentEditor.refresh(tEd);

   // this is SLOW
   var tCursor = new Object;
   tCursor.pos = 0;
   var sFormattedXML;
   if (event.ctrlKey)
      sFormattedXML = XUIDebugger.formatNode(saw.getXmlText(XUIGetColumnSpace()), tCursor, 0);
   else if (event.altKey)
      sFormattedXML = XUIDebugger.formatNode(saw.getXmlText(XUICaptionSpace.xmlElement), tCursor, 0);
   else
      sFormattedXML = XUIDebugger.formatNode(saw.getXmlText(tEd.element), tCursor, 0);
   tEd.textArea.value = sFormattedXML.replace(/^\r\n/,"");
   tEd.textArea.wrap = "off";
}

///////////////////////////////////////////////////////////////////////////////
// Preview Editor
///////////////////////////////////////////////////////////////////////////////

//-----------------
function XUIPreviewer(editorID)
{
   this.init(editorID);
}

XUIPreviewer.prototype = new XUIEditor();

//-----------------
// Init function provided so derived functions can call base previewer init
XUIPreviewer.prototype.init = function(editorID)
{
   if (editorID == null)
      return;

   this.previewDiv = document.getElementById(editorID + 'PreviewDiv');
   this.previewResultDiv = document.getElementById(editorID + 'IFrame');
   
   this.checkbox = document.getElementById(editorID + 'Checkbox');
   this.span = document.getElementById(editorID + 'Span');
   this.form = document.forms[editorID + 'Form'];
   this.form.action = saw.commandToURL("ViewPreview");
   this.eid = editorID;
   this.bIsLoading  = false;
}

//-----------------
// The previewer sets the autoPreview attribute of the persistElement depending on the check
// box.
XUIPreviewer.prototype.load = function(xmlElement, persistElement)
{
   if (this.previewDiv == null)
      alert('Derived Previewer needs to set this.previewDiv or include kuiXUIPreviewer');

   this.report = xmlElement;
   this.view = persistElement;

   if (this.checkbox != null)
      this.checkbox.checked = this.view.getAttribute("autoPreview") != "false";

   if (this.isAuto())
      this.preview();
   else
   {
      this.showPreviewing(false);
      this.resultsAvailable();
   }
}

//-----------------
XUIPreviewer.prototype.apply = function()
{
   if (this.bIsLoading == true)
   {
      //alert('Hahaha, you better wait until loading is completed to continue.');
      return false;
   }
   else // No apply for previewer
      return true;
}

//-----------------
// Override this if you don't want to clear the div entirely
XUIPreviewer.prototype.clearPreview = function()
{
   this.previewDiv.innerHTML/*innerText*/ = "";
}

XUIPreviewer.prototype.stopPreview = function()
{
   //stop loading any onloading pages. 
   if (this.previewResultDiv)
      this.previewResultDiv.src = saw.getEmptyHtm();
   //remove the retrieving message
   this.showPreviewing(false);  
}

//-----------------
XUIPreviewer.prototype.isAuto = function()
{
   if (this.checkbox != null)
      return (this.checkbox.checked);
   else
      return true;
}

//-----------------
XUIPreviewer.prototype.showPreviewing = function(bVisible)
{
   this.span.style.visibility = bVisible ? "inherit" : "hidden";
}

//-----------------
XUIPreviewer.onClick = function(eid)
{
   var tDiv = XUIPanel.getDiv(eid);
   
   
   if (tDiv.editor.view)
      tDiv.editor.view.setAttribute("autoPreview", "true");
   
   if (tDiv.editor.checkbox)
      tDiv.editor.checkbox.checked = true;   
   tDiv.editor.parentEditor.refresh(tDiv.editor);
   tDiv.editor.ignoreServerCall = false;
   tDiv.editor.displayClicked = true;
   tDiv.editor.preview();

   return false;
}

//-----------------
XUIPreviewer.onCheck = function(eid)
{
   var tDiv = XUIPanel.getDiv(eid);

   tDiv.editor.view.setAttribute("autoPreview", tDiv.editor.isAuto() ? "true" : "false");

   if (tDiv.editor.isAuto())
   {
      tDiv.editor.parentEditor.refresh(tDiv.editor);
      tDiv.editor.ignoreServerCall = false;
      tDiv.editor.preview();
   }
   else
   {
      tDiv.editor.ignoreServerCall = true;
      tDiv.editor.stopPreview();
      tDiv.editor.clearPreview();
   }
}

//-----------------
XUIPreviewer.prototype.preview = function()
{
   if((this.report == null) || (this.handlingResults == true))
      return;

   this.showPreviewing(true);

   this.form.action = saw.commandToURL("ViewPreview");
   this.form.ReportXML.value = saw.getXmlText(this.report);

   if ((AnswersResultsEditor != undefined) && (AnswersResultsEditor.bRefreshData == true))
   {
      AnswersResultsEditor.bRefreshData = false;
      if (this.form.Action != undefined)
         this.form.Action.value = "Refresh";
   }

   var sError = null;

   // Validate UI

   if (sError != null)
   {
      this.showPreviewing(false);
      this.previewDiv.innerHTML = "<b>" + sError + "</b>";
   }
   else
   {
      this.form.submit();
   }
}

//-----------------
// Abstract method if overriding previewer
XUIPreviewer.prototype.resultsAvailable = function()
{
}

//-----------------
// This method is called by the server preview result page
XUIPreviewer.handleResults = function(fromFrame, fromDiv, eid)
{   
   var tDiv = XUIPanel.getDiv(eid);
   if (tDiv && tDiv.editor)
   {
      //Check if it is "Searching".
      var tIDDiv = fromDiv.ownerDocument.getElementById("idStateID");
      if (tIDDiv)
      {
         var sId = tIDDiv.getAttribute("value");
         var tResultDiv = fromDiv.ownerDocument.getElementById(sId + "Result");
         if (tResultDiv && (tResultDiv.getAttribute("result") == "searching"))
            return;
      }

      if (!tDiv.editor.ignoreServerCall)
      {
         var toDiv = tDiv.editor.previewDiv;

         toDiv.innerHTML = fromDiv.innerHTML;

         var aScripts = toDiv.getElementsByTagName('SCRIPT');

         for(var i = 0 ; i != aScripts.length ; ++i)
         {
            if (aScripts[i].innerHTML && aScripts[i].getAttribute("userDefined") != "true" && aScripts[i].htmlFor == "")
            {
               window.eval(aScripts[i].innerHTML);
            }
         }
      }

      tDiv.editor.showPreviewing(false);

      // Default behavior is to call resultsAvailable on myself (so I can be overriden by another
      // editor, but if my parent has a handleUpdatedReport function I will call that instead
      var tIsland = saw.getXmlIsland("idUpdatedReport", fromFrame, fromFrame);
      var tResponse = (saw.checkObjectReference(tIsland) ? tIsland.firstChild : null);

      if (saw.checkObjectReference(tResponse))
      {
         // We need to make sure handleUpdateReport doesn't cause another preview
         // so we'll set a flag while we handle it
         tDiv.editor.handlingResults = true;

         if (saw.checkObjectReference(tDiv.editor.parentEditor) && (tDiv.editor.parentEditor.handleUpdatedReport != null))
            tDiv.editor.parentEditor.handleUpdatedReport(tResponse);
         else
            tDiv.editor.resultsAvailable(tResponse);

         // Ok, clear the flag
         tDiv.editor.handlingResults = false;
      }
      else
         tDiv.editor.resultsAvailable(null);
   }
}

//-----------------
// This method can be called by the previewer to replace the report and column space after
// a drill has occurred.
XUIPreviewer.replaceReportAndColumnSpace = function(primaryReport, xmlResult)
{
   // We're here, so that means we need to replace the whole damn report
   // alert('handleUpdatedReport');

   // Lets get the report
   var tReport = xmlResult.selectSingleNode("saw:report");
   if (tReport == null)
      return;

   // Ok, well we can't just replace our report node because my parent won't notice, so instead
   // lets replace the appropriate children
   var tCriteria = tReport.selectSingleNode("saw:criteria");
   if (tCriteria != null)
      XUIReplaceOrAppendChild(primaryReport, tCriteria);

   var tViews = tReport.selectSingleNode("saw:views");
   if (tViews != null)
      XUIReplaceOrAppendChild(primaryReport, tViews);

   // Ok, Ok, now replace the columnSpace
   var tColumnSpace = xmlResult.selectSingleNode("saw:columnSpace");
   if (tColumnSpace != null)
   {
      XUIColumnSpace.setColumnSpaceElement(tColumnSpace);
   }
}

//-----------------
function XUIPanel()
{
}

//-----------------
XUIPanel.getDiv = function(eid)
{
   var tDiv = document.getElementById(eid + 'Div');
   //if (tDiv == null)
   //   alert ('Unable to find div ' + eid + 'Div');

   return tDiv;
}

//-----------------
XUIPanel.getPanel = function(eid)
{
   var tDiv = XUIPanel.getDiv(eid);
   if (tDiv != null)
      return tDiv.panel;
}

//-----------------
XUIPanel.getEditor = function(eid)
{
   var tDiv = XUIPanel.getDiv(eid);
   if (tDiv != null)
      return tDiv.editor;
}

//-----------------
// This is called by a form onsubmit so that it can call the onSubmit on the appropriate
// panel object.

XUIPanel.onSubmit = function(eid, event)
{
   var tDiv = XUIPanel.getDiv(eid);
   return tDiv.panel.onSubmit(event);
}

//-----------------
// This is called by a form onsubmit so that it can call the onSubmit on the appropriate
// panel object.

XUIPanel.onChange = function(eid)
{  
   var tPanel = XUIPanel.getPanel(eid);
   return tPanel.onChange(tPanel.editor);
}

//-----------------
XUIPanel.prototype.init = function(eid, tEditor, parentEditor)
{
   var tDiv = XUIPanel.getDiv(eid);
   if (tDiv == null)
   {
      alert("Panel Div '" + eid + "' not found in document.");
      return null;
   }

   tEditor.panel = this; // set the panel into the editor
   tEditor.parentEditor = parentEditor;

   tDiv.panel = this; // set the panel object into the div
   tDiv.editor = tEditor; // set the editor object into the div

   this.div = tDiv;
   this.editor = tDiv.editor; // convenience

   return tDiv;
}

//-----------------
XUIPanel.prototype.getXMLElement = function()
{
   return this.editor.element;
}

//-----------------
// Loads the element into the UI.  The editor load is also called by init, but this allows
// the parent to replace the element the editor is using.

XUIPanel.prototype.load = function(xmlElement, refElement)
{
   this.editor.load(xmlElement, refElement);
}

//-----------------
// Tell the editor to apply its changes and then notify its parent.

XUIPanel.prototype.apply = function(bAlreadyApplied, event)
{
   if (bAlreadyApplied || this.editor.apply(null, event))
   {
      if (this.editor.parentEditor != null)
         this.editor.parentEditor.onChildApply(this.editor, event);

      return true;
   }
   else
      return false;
}

//-----------------
// Cancel the changes and close the dialog.

XUIPanel.prototype.discard = function(event)
{
   return this.editor.discard(event);
}

//-----------------
// usually just ignore the enter key.  XUIDialog overrides of course.

XUIPanel.prototype.onSubmit = function() // virtual
{
   return false;
}

//-----------------
// Base Panel does nothing but notify the associated editor

XUIPanel.prototype.onChange = function(sourceEditor) // virtual
{
   return this.editor.onChange(sourceEditor);
}

//-----------------
XUIPanel.prototype.focus = function()
{
   // focus the editor
   this.editor.focus();
}

//-----------------
XUIPanel.prototype.disable = function()
{
   this.div.style.cursor = "wait";
}

//-----------------
XUIPanel.prototype.enable = function()
{
   this.div.style.cursor = "";
}

//-----------------
// hide or show the panel's div
XUIPanel.prototype.display = function(bVisible)
{
   this.div.style.display = (bVisible == true) ? '' : 'none';
}

//-----------------
//-- XUIInline
//-----------------
// This object displays an editor inlined in the document, wrapped in a div.
//-----------------
function XUIInline(eid, tEditor, parentEditor)
{
   this.init(eid, tEditor, parentEditor);
}

XUIInline.prototype = new XUIPanel();

//-----------------
// Inline Panel can notify all parent editors by calling their onChange method.  Editors
// can call this if they don't want their own onChange called.

XUIInline.prototype.notifyParent = function(sourceEditor)
{
   var tParent = this.editor.parentEditor;
   if (tParent != null)
   {
      tParent.panel.onChange(sourceEditor);
   }
}

//-----------------
// Inline Panel notifies the associated editor and all parent editors onChange unless the
// editors onChange returns false

XUIInline.prototype.onChange = function(sourceEditor)
{
   // notify editor
   if (this.editor.onChange(sourceEditor) != false)
   {
      this.notifyParent(sourceEditor);
   }
}

//-----------------
//-- XUIPage
//-----------------
function XUIPage(eid, tEditor)
{
   var tDiv = this.init(eid, tEditor);
}

XUIPage.prototype = new XUIPanel();

//-----------------
// Loads the element into the UI.  The editor load is also called by init, but this allows
// the parent to replace the element the editor is using.

XUIPage.prototype.load = function(xmlElement)
{
   var tDiv = this.div;
   tDiv.editor.load(xmlElement);
   tDiv.editor.focus();
}

//-----------------
XUIPage.prototype.onSubmit = function(event)
{
   return (this.apply());
}

//-----------------
// Apply the changes and if successful, close the dialog.

XUIPage.ok = function(eid)
{
   var tDiv = XUIPanel.getDiv(eid);
   tDiv.panel.apply();

   return false;
}

//-----------------
// Cancel the changes and close the dialog.

XUIPage.cancel = function(eid)
{
   var tDiv = XUIPanel.getDiv(eid);
   tDiv.panel.discard();

   return false;
}

//-----------------
//-- XUIDiaglog
//-----------------
// This object displays a dialog containing the editor.  It makes a copy of the element for
// the editor to use and discards changes if cancel is selected.
//-----------------

//-----------------
// Create a dialog object and set it and the editor into the dlg div, and then init the
// editor with a copy of the node.  Parent if any is notified on some events.

function XUIDialog(eid, tEditor, parentEditor)
{
   this.init(eid, tEditor, parentEditor);
}

XUIDialog.prototype = new XUIPanel();

function positionX(dialog, xPos, bHardCodedXPos)
{
   if(saw.isRToL())
      positionXRToL(dialog, xPos, bHardCodedXPos);
   else
      positionXLToR(dialog, xPos);
}

function positionXLToR(dialog, xPos)
{
   xPos = (xPos >= -1) ? xPos : 15;
   xPos -= saw.calcAbsoluteLeftOffsetParent(dialog.div.parentNode);
   dialog.div.style.left = "0px";
   
   if (xPos==-1)
   {
      xPos=Math.round((document.body.parentNode.clientWidth-dialog.div.clientWidth)/2);
   }
   else
   {
      if (xPos+dialog.div.clientWidth>document.body.clientWidth)
         xPos=document.body.clientWidth-dialog.div.clientWidth;
   }
   
   dialog.div.style.left = ((saw.getDocumentScrollLeft()+xPos >= 0) ? saw.getDocumentScrollLeft()+xPos : 0)+"px";
}

function positionXRToL(dialog, xPos, bHardCodedXPos)
{
   var cw = document.documentElement.clientWidth;
   var sl = document.body.offsetWidth - cw - document.documentElement.scrollLeft;
   var dw = dialog.div.clientWidth;
   var maxLeft = cw + sl;
   var maxRight = sl;
   
   if(bHardCodedXPos == null)
      bHardCodedXPos = false;
     
   xPos = (xPos >= -1) ? xPos : 15;
   
   if(-1 == xPos)
      dialog.div.style.right = maxRight + Math.round((cw - dw)/2) + "px";
   else
   {
      var topRight;
      if(bHardCodedXPos)
        topRight = maxRight + xPos;
      else
        topRight = maxLeft - xPos;

      maxLeft -= 16;  // width of the vertical bar
      if(topRight + dw > maxLeft)
         dialog.div.style.right = maxLeft - dw + "px";
      else
         dialog.div.style.right = topRight + "px";
   }
}

//-----------------
// Display the dialog.

XUIDialog.prototype.show = function(xmlElement, xPos, yPos, refElement, clickedItem, bChild, bHardCodedXPos, bAutoCloseable)
{
   this.div.style.visibility = 'hidden';
   this.div.style.display = 'block';
   this.editor.load(xmlElement, refElement);

   // return if the dialog is already displayed
   //if (this.div.style.display != 'none')
   //   return;
   
   var sl = document.documentElement.scrollLeft;
   var cw = document.documentElement.clientWidth;
   var bo = document.body.offsetLeft;
   
   // if not specified assume child modal dialog
   if(bChild == null)
      bChild = true;

   this.isChild = bChild;

   yPos = (yPos >= -1) ? yPos : 15;

   yPos -= saw.calcAbsoluteTopOffsetParent(this.div.parentNode);

   this.div.style.position = 'absolute';
   this.div.style.top = "0px";
   //this.div.style.display = 'block';
   this.div.style.visibility = 'visible';

   this.editor.onDisplay();

   if (yPos==-1)
   {
      yPos=Math.round((document.body.parentNode.clientHeight-this.div.clientHeight)/2);
   }
   else
   {
      if (yPos+this.div.clientHeight > saw.getClientHeight())
         yPos=saw.getClientHeight() - this.div.clientHeight;
   }

   this.div.style.top = ((saw.getDocumentScrollTop()+yPos >= 0) ? saw.getDocumentScrollTop()+yPos : 0)+"px";
   positionX(this, xPos, bHardCodedXPos);

    //Determine next zIndex to use
    //var npz = (this.editor.parentEditor == null) ? 100 : this.editor.parentEditor.panel.div.style.zIndex + 1;

    //Set the zIndex of div and its panels
   //this.div.style.zIndex = npz;
   //var aDivs = this.div.getElementsByTagName("DIV");
   //for (id = 0; id != aDivs.length; ++id)
   //   aDivs[id].style.zIndex = npz;

   if (clickedItem != null)
      NQWPositionPopup(clickedItem, this.div);

   // hide selects behind this div.
   XUIDialog.disableSelects(this.div);  // fix selects bleed through the transparent layer in IE
   saw.hideSelects(this.div);

   // doing this because solaris mozilla flash is not transparent
   if (is_nav)
      saw.hideCharts(this.div);

   this.editor.onMove(saw.calcAbsoluteLeft(this.div), saw.calcAbsoluteTop(this.div));

   //we have to move the focus to the dialog, otherwise type enter key 
   // before the dialog gets the focus may cause problem.
   
   if (this.div.focus) //firefox doesn't seem to support focus() on divs
      this.div.focus();
   if (this.div.blur)  //firefox doesn't seem to support blur() on divs
      this.div.blur();

   this.editor.focus();

   showDialog(this.div.id, this.editor.eid, bChild, bAutoCloseable);
}

//-----------------
XUIDialog.prototype.onSubmit = function(event)
{
   if (this.apply())
      this.close();

   // return false always since we don't want the form to submit
   return false;
}

//-----------------
// Close the dialog

XUIDialog.prototype.close = function()
{
   // show selects behind this div.
   XUIDialog.enableSelects(this.div);
   saw.showSelects(this.div);

   if (is_nav)
      saw.showCharts(this.div);
   hideDialog(this.div.id, false);
}

//-----------------
// Changes the dimensions of the dialog to parameters provided.
XUIDialog.prototype.setSize = function (nWidth, nHeight)
{
   if (!nWidth)
      nWidth = 200;
   if (!nHeight)
      nHeight = 200;

   this.div.style.width = nWidth + "px";
   this.div.style.height = nHeight + "px";
}

//-----------------
// Apply the changes and if successful, close the dialog.

XUIDialog.ok = function(eid, event)
{
   var tDiv = XUIPanel.getDiv(eid);
   // guard against spurious divs (Calendar, for instance, when an ESC is captured)
   if (null != tDiv && null != tDiv.panel)
   {
      if (tDiv.panel.apply(false, event))
         tDiv.panel.close();
   }

   return false;
}

//-----------------
// Cancel the changes and close the dialog.

XUIDialog.cancel = function(eid, event)
{
   var tDiv = XUIPanel.getDiv(eid);
   // guard against spurious divs (Calendar, for instance, when an ESC is captured)
   if (tDiv)
   {
      if(tDiv.panel)
      {
          var tReturn = tDiv.panel.discard(event);
          if (null == tReturn || tReturn == true)
             tDiv.panel.close();
      }
      else
        tDiv.style.display = "none";
   }

   return false;
}

function XUICloseActiveDiv()
{
    if (bActiveDivIsCloseable &&  activeDiv != null && saw.checkObjectReference(activeDiv.panel))
        activeDiv.panel.close(); 
}

//-----------------
// Cancel the changes and close the dialog.

XUIDialog.isVisible = function(eid)
{
   var tDiv = XUIPanel.getDiv(eid);
   if (tDiv != null)
      return tDiv.style.display != 'none';
   else
      return false;
}

XUIDialog.enableSelects = function(tObj)
{
   if(is_ie)
   {
       var aSelects = document.getElementsByTagName("SELECT");
       for(var s = 0 ; s != aSelects.length ; ++s)
       {
          var tElement = aSelects[s];
          if(tElement.oldEnabled && tElement.activeObject == tObj)
          {
             tElement.disabled = false;
             tElement.oldEnabled = null;
          }
       }
   }
}

XUIDialog.disableSelects = function(tObj)
{
   if(is_ie)
   {
       var aObjs = document.getElementsByTagName("SELECT");

       for(var s = 0 ; s != aObjs.length ; ++s)
       {
          var tElement = aObjs[s];

         if(tElement.oldEnabled == null && !saw.isDescendantOf(tObj, tElement))
         {
            var tParent = tElement;
            var bParentVisible = true;
            
            while(tParent != null)
            {
               if(tParent.style != undefined && tParent.style.display == 'none')
               {
                  bParentVisible = false;
                  break;
               }

               tParent = saw.getParentElement(tParent);
            }

            if(bParentVisible && tElement.disabled != true)
            {
               tElement.oldEnabled = true;
               tElement.activeObject = tObj;
               tElement.disabled = true;
            }
         }
       }
   }
}

//-----------------
//-- XUIMenu
//-----------------
// This object displays a menu containing the editor.  It wrappers the code found in menu.js
//-----------------

//-----------------
// Create a dialog object and set it and the editor into the dlg div, and then init the
// editor with a copy of the node.  Parent if any is notified on some events.

function XUIMenu(eid, tEditor, parentEditor)
{
   this.init(eid, tEditor, parentEditor);
}

//-----------------
// Display the dialog.

XUIMenu.prototype.show = function(xmlElement, xPos, yPos, refElement)
{
   this.editor.load(xmlElement, refElement);

   this.div.style.position = 'absolute';
   this.div.style.left = (xPos != null) ? xPos : 12;
   this.div.style.top = (yPos != null) ? yPos : 12;

   this.div.style.display = '';

   this.editor.focus();
}

//-----------------
XUIMenu.prototype.onSubmit = function(event)
{
   if (this.apply())
      this.close();

   // return false always since we don't want the form to submit
   return false;
}

//-----------------
// Close the dialog

XUIMenu.prototype.close = function()
{
   this.div.style.display = 'none';
}

//-----------------
// Apply the changes and if successful, close the dialog.

XUIMenu.ok = function(eid)
{
   var tDiv = XUIPanel.getDiv(eid);
   tDiv.panel.apply();
   tDiv.panel.close();

   return false;
}

//-----------------
// Cancel the changes and close the dialog.

XUIMenu.cancel = function(eid)
{
   var tDiv = XUIPanel.getDiv(eid);
   tDiv.panel.discard();
   tDiv.panel.close();

   return false;
}

//-----------------
// Cancel the changes and close the dialog.

XUIMenu.isVisible = function(eid)
{
   var tDiv = XUIPanel.getDiv(eid);
   if (tDiv != null)
      return tDiv.style.display != 'none';
   else
      return false;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Server Call - used to retrieve XML from server
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

//-----------------
function XUIServerCall(editorID)
{
   this.iframeID = editorID + "IFrame";
   //this.iframeID = 'XUIServerCallIFrame';

   var tIFrame = document.getElementById(this.iframeID);

   if (tIFrame == null)
   {
      //alert('You need to include kuiServerCall on your page and make sure you are using the correct eid');

      tIFrame = saw.createHiddenIFrame(this.iframeID, this.iframeID);

      // For debugging
      //tIFrame.style.display = '';
      //tIFrame.style.visibility = "visible";
      //tIFrame.style.height = '300px';
      //tIFrame.style.width = '300px';

      //tIFrame.onLoad = "XUIServerCall.onLoad(event)";
      saw.addEventListener(tIFrame, 'load', XUIServerCall.onLoad);

   }

   tIFrame.editor = this;
   this.iframe = tIFrame;
   // SAL: what's the messageCell for? Not used anywhere, so comment out
   //this.messageCell = document.getElementById(editorID + "Cell");
}

//-----------------
// This method issues the form in the iFrame
XUIServerCall.prototype.execute = function(tCaller, tForm, sAction, tContext)
{
   // save caller and specified context
   this.caller = tCaller;
   this.callerContext = tContext;

   this.caller.panel.disable();

   tForm.target = this.iframeID;

   tForm.method = "post";

   if (saw.checkObjectReference(sAction) && sAction.length > 0)
      tForm.action = saw.commandToURL(sAction);

   tForm.submit();
}

//-----------------
// This is called when the iframe returns, and calls validated on the calling editor.  This
// assumes an XML Island id = "idXUI" and a root element "nqw" containing one "response"
// node which is passed to the caller. For example, if the returned page has content like
// <xml><nqw><stuff/></nqw></xml>, then <stuff/> will be passed to the caller.

// event is not attached to target when using event listener
XUIServerCall.onLoad = function(event /*eid*/)
{
   var sIFrameID = saw.getEventCurrentTarget(event).id;
   var tIFrame = window.frames[sIFrameID];
   var tEditor = document.getElementById(sIFrameID).editor;

   if ((tIFrame != null) && (tEditor != undefined))
   {
      var tCaller = tEditor.caller;

      var tResponse = null;
      var sMsg = null;

      try
      {
         //var tDoc = saw.getContentDocument(tIFrame);

         var tIsland = saw.getXmlIsland("idXUI", tIFrame, tIFrame);

         var tNQW = (saw.checkObjectReference(tIsland) ? tIsland.firstChild : null);

         tResponse = tNQW.selectSingleNode("saw:error");

         if (!tResponse)
            tResponse = (saw.checkObjectReference(tNQW) ? saw.getFirstChildElement(tNQW) : null);

         if (tResponse == null)
         {
            // Logic error??
            sMsg = 'Invalid response received: ' + tIFrame.document.body.innerHTML;
         }
      }
      catch(e)
      {
         // SAL: IE doc says 'description' is the right property to use here
         // ms-help://MS.VSCC/MS.MSDNVS/script56/html/js56jsobjError.htm
         sMsg = e.description;
      }

      var tCallerContext = tEditor.callerContext;

      // deletes the browser's history entry for iframe
      // currently removeIFrame doesn't do anything when using Mozilla
      // If this functionality is added for Mozilla, we shoud check if removeIFrame invalidates the tIsland reference
      saw.removeIFrame(sIFrameID);

      if (tResponse == null)
         tCaller.serverResponse(false, sMsg, tCallerContext);
      else if (tResponse.nodeName == "saw:error")
         tCaller.serverResponse(false, XUIGetElementText(tResponse), tCallerContext);
      else
         tCaller.serverResponse(true, tIsland.firstChild, tCallerContext);

      tCaller.panel.enable();
   }
}

/////////////////////////////////////////////////////////////////////////////
// Horizontal Tabs 
/////////////////////////////////////////////////////////////////////////////

function XUIHozTabControl(eid)
{
   this.eid = eid;
   this.tabList = document.getElementById(this.eid+'TabList');
   this.contentPanel = document.getElementById(this.eid+'ContentPanel');
   this.magicDiv = document.getElementById(this.eid+'MagicDiv');
   this.currentTab = null;
}

XUIHozTabControl.prototype.init = function()
{
   var tDiv = document.getElementById(this.eid+'Div');
   tDiv.style.display = '';
   tDiv.hozTabEditor = this;
   this.activateTab(0);
}

XUIHozTabControl.prototype.appendTab = function(sTabCaption, sTabHint, tTabStuff)
{
   var tLI = document.createElement('LI');
   this.tabList.appendChild(tLI);
   var tabIndex = this.tabList.childNodes.length-1;
   //alert(sTabHint);
   var tA = document.createElement('A');
   tA.href = 'javascript:void(null)';
   func = new Function('XUIHozTabControl.onActivateTab("'+ this.eid + '","' + tabIndex + '"); return false');
   saw.addEventListener(tA, 'click', func);
   tA.appendChild(document.createTextNode(sTabCaption));

   tLI.appendChild(tA);
   tLI.setAttribute('sawHozTabHint', sTabHint);
   this.contentPanel.appendChild(tTabStuff);
}

XUIHozTabControl.prototype.removeAllTabs = function()
{
   if (this.tabList.hasChildNodes())
      XUIRemoveAllChildren(this.tabList);
      
   if (this.contentPanel.hasChildNodes())
      XUIRemoveAllChildren(this.contentPanel);
}

XUIHozTabControl.prototype.getTabIndex = function(tabHint)
{
   if (tabHint != null)
   {
      var tList = this.tabList.getElementsByTagName('LI');
      for (var i=0;i<tList.length;i++)
      {
         //alert(tList[i].getAttribute('sawHozTabHint'));
         if (tList[i].getAttribute('sawHozTabHint') == tabHint)
            return i;
      }
   }
   
   return null;
}

XUIHozTabControl.prototype.activateThruHint = function(tabHint)
{
   
    var tIndex = this.getTabIndex(tabHint);
    //alert(tIndex);
    if (tIndex != null)
      this.activateTab(tIndex);
    
}

XUIHozTabControl.prototype.activateTab = function(tabIndex)
{
   var tList = this.tabList.getElementsByTagName('LI');
   if ((tabIndex == 'undefined') || (tabIndex == null) ||
       (tabIndex < 0) || (tabIndex >= tList.length))
      return;
   
   var tDivList = this.contentPanel.getElementsByTagName('DIV');
   for (var i=0;i<tDivList.length;i++)
   {
      tDivList[i].style.display =  ( i == tabIndex)?'':'none';
      
   }
   
   for (var i=0;i<tList.length;i++)
   {
      if ( i != tabIndex)
         tList[i].className = 'SAWHozTabOff';
   }
   
   var tLI = tList[tabIndex];
   tLI.className = 'SAWHozTabCurrent';
 /*  
   this.magicDiv.style.display ='';
   this.magicDiv.style.position = 'absolute';
   this.magicDiv.style.backgroundColor = 'white';
   
   
   
   this.magicDiv.style.width = 3 + "px";
   
   if (is_ie)
   {
      this.magicDiv.style.top = saw.calcAbsoluteTop(tLI) - saw.calcAbsoluteTopOffsetParent(tLI) + 3+"px";
      
      if (saw.isRToL())
      {
         this.magicDiv.style.left = saw.calcAbsoluteLeft(this.contentPanel) - saw.calcAbsoluteLeftOffsetParent(this.contentPanel) + this.contentPanel.offsetWidth -tLI.offsetWidth+1+"px";
         
      }
      else
         this.magicDiv.style.left = saw.calcAbsoluteLeft(this.contentPanel) - saw.calcAbsoluteLeftOffsetParent(this.contentPanel) + 1+"px";
      this.magicDiv.style.height = (tLI.offsetHeight >= 2)?tLI.offsetHeight -2:0 + "px";
   }
   else
   {
      this.magicDiv.style.top = saw.calcAbsoluteTop(tLI) - saw.calcAbsoluteTopOffsetParent(tLI) + 1+ "px";
      if (saw.isRToL())
      {
      
         this.magicDiv.style.left = saw.calcAbsoluteLeft(this.contentPanel) - saw.calcAbsoluteLeftOffsetParent(this.contentPanel) + this.contentPanel.offsetWidth -tLI.offsetWidth+5+"px";
      }
      else
         this.magicDiv.style.left = saw.calcAbsoluteLeft(this.contentPanel) - saw.calcAbsoluteLeftOffsetParent(this.contentPanel) -1+"px";
      this.magicDiv.style.height = tLI.offsetHeight -2 + "px";
      
      
   }
   this.magicDiv.style.zIndex = 2;
   */
   this.currentTab = tabIndex;
}

XUIHozTabControl.onActivateTab = function (eid, tabIndex)
{
   var tDiv = document.getElementById(eid + 'Div');
   
   tDiv.hozTabEditor.activateTab(tabIndex);
}

///////////////////////////////////////////////////////////////////////////////
// Property Pages - enableTab/disableTab MUST be called before init
///////////////////////////////////////////////////////////////////////////////

//-----------------
function XUIPropertyPagesControl(eid)
{
   this.eid = eid;
}

//-----------------
XUIPropertyPagesControl.prototype.init = function()
{
   var eid = this.eid;

   var tPropPage = document.getElementById(eid);

   tPropPage.propPage = this;

   var tDivCell = tPropPage.rows[1].cells[0];

   var tTallestDiv = null;
   var tWidestDiv = null;

   tDivCell.style.display = '';

   for (var i = tDivCell.firstChild; i != null; i = i.nextSibling)
   {
      if ((i.nodeName != 'DIV') || (i.tabDisabled == 'true'))
         continue;

      if (tTallestDiv == null)
         tTallestDiv = i;
      else if (tTallestDiv.offsetHeight < i.offsetHeight)
         tTallestDiv = i;

      if (tWidestDiv == null)
         tWidestDiv = i;
      else if (tWidestDiv.offsetWidth < i.offsetWidth)
         tWidestDiv = i;
   }

   if (tTallestDiv == null) // I am empty
      return;

   var nMaxHeight = tTallestDiv.offsetHeight;
   var nMaxWidth = tTallestDiv.offsetWidth;

   for (var i = tDivCell.firstChild; i != null; i = i.nextSibling)
   {
      if ((i.nodeName != 'DIV') || (i.tabDisabled == 'true'))
         continue;

      i.style.height = nMaxHeight +"px";
      i.style.width = nMaxWidth +"px";
   }

   var sTab = '';

   // if the tab displayed last still exists, then
   if ((tPropPage.lastTab != null) && (document.getElementById(eid+tPropPage.lastTab).tabDisabled != true))
      sTab = tPropPage.lastTab;
   else
   {
      var n = 1;

      while (n <= 6)
      {
         var sTestTab = 'tab'+n;
         var tTab = document.getElementById(eid+sTestTab);
         if (tTab == null)
            break;
         if (tTab.tabDisabled != true)
         {
            sTab = sTestTab;
            break;
         }
         else
            ++n;
      }
   }

   if (sTab != '')
      this.activateTab(sTab);
}

//-----------------
XUIPropertyPagesControl.prototype.removeAllTabs = function()
{
   var tTabsTable = document.getElementById(this.eid+'PropTabs');

   var tRow = tTabsTable.rows[0];

   while (tRow.firstChild != null)
      tRow.removeChild(tRow.firstChild);

   var tDivsCell = document.getElementById(this.eid).rows[1].cells[0];

   while (tDivsCell.firstChild != null)
      tDivsCell.removeChild(tDivsCell.firstChild);

   document.getElementById(this.eid).lastTab = null;
}

//-----------------
XUIPropertyPagesControl.prototype.appendTab = function(sTabCaption, sTabHint, tTabStuff, onDisplay, onDisplayContext)
{
   var tTabsTable = document.getElementById(this.eid+'PropTabs');

   var tRow = tTabsTable.rows[0];

   var tSpacer = document.createElement('TD');
   tSpacer.className = 'SAWPropPgTabSpacer';
   tSpacer.innerHTML = '&nbsp;';

   var sTab = 'tab'+(tRow.cells.length/2+1);

   var tTab = document.createElement('TD');
   tTab.id = this.eid+sTab;
   tTab.className = 'SAWPropPgTabCell';
   var tSpan1 = document.createElement('SPAN');
   tSpan1.className = 'SAWPropPgTabOuter';
   var tSpan2 = document.createElement('SPAN');
   tSpan2.className = 'SAWPropPgTabOff';
   var tA = document.createElement('A');
   tA.href = 'javascript:void(null)';
   var func = new Function('XUIPropertyPagesControl.onActivateTab("' + this.eid + '","' + sTab + '"); return false');
   saw.addEventListener(tA, 'click', func);
   tA.appendChild(document.createTextNode(sTabCaption));
   tSpan2.appendChild(tA);
   tSpan1.appendChild(tSpan2);
   tTab.appendChild(tSpan1);

   tRow.appendChild(tSpacer);
   tRow.appendChild(tTab);

   var tTabDiv = document.createElement('DIV');
   tTabDiv.id = this.eid+sTab+'Div';
   tTabDiv.className='SAWPropPgDiv';
   if (sTabHint != null)
      tTabDiv.setAttribute('sawTabHint', sTabHint);
   tTabDiv.appendChild(tTabStuff);

   // this may not work on Mozilla??
   tTabDiv.onDisplay = onDisplay;
   tTabDiv.onDisplayContext = onDisplayContext;

   var tPropPageTable = document.getElementById(this.eid);
   tPropPageTable.rows[1].cells[0].appendChild(tTabDiv);
}

//-----------------
XUIPropertyPagesControl.prototype.getLastTab = function()
{
   var eid = this.eid;

   var tPropPage = document.getElementById(eid);

   var sTab = '';
   if (null != tPropPage && null != tPropPage.lastTab)
      sTab = tPropPage.lastTab;

   return sTab;
}

//-----------------
XUIPropertyPagesControl.prototype.getCurrentTabHint = function()
{
   var sLastTab = this.getLastTab();

   if (sLastTab.length == 0)
      sLastTab = 'tab1';

   var div = document.getElementById(this.eid+sLastTab+'Div');

   return div.getAttribute('sawTabHint');
}


//-----------------
XUIPropertyPagesControl.prototype.enableTab = function(nTabIndex)
{
   this.disableTabImpl(nTabIndex,false);
};

//-----------------
XUIPropertyPagesControl.prototype.disableTab = function(nTabIndex)
{
   this.disableTabImpl(nTabIndex,true);
};

//-------------------
XUIPropertyPagesControl.resizePropertyPages = function(editor)
{
   // SAL - Bug 8413741
   // It appears that something else has changed in the DOM structure, which is forcing us to
   // recompute this for IE as well.
   //if (is_ie)
   //   return;
      
   var tEditor = editor;
   if (typeof(editor) == 'string')
      tEditor = XUIPanel.getEditor(editor);
   
   var tPropPages = tEditor.propertyPages;
   if (!tPropPages && tEditor.parentEditor)
      tPropPages = tEditor.parentEditor.propertyPages;
      
   if (tPropPages)
      tPropPages.resize();
}

//-----------------
XUIPropertyPagesControl.prototype.resize = function()
{
   // This control sets an absolute width on the dialog panel.
   // If a tab's contents dynamically change, call this method to allow
   // the panel to expand in size.
   // (FR 12-1AGW1V8, 12-1FN5ITP - Mozilla only)
   // SAL - Bug 8413741
   // It appears that something else has changed in the DOM structure, which is forcing us to
   // recompute this for IE as well.   
   //if (!is_ie)
   {
      var sTab = this.getLastTab();
      if (!sTab)
         return;

      // Faster alternative to this.activateTab(sTab);
      var tabDiv = document.getElementById(this.eid + sTab + 'Div');
      var pxIndex = tabDiv.style.width.indexOf("px");
      if (pxIndex > 0)
      {
         // Use auto if old width is too small.
         var oldWidth = tabDiv.style.width.substring(0, pxIndex);
         tabDiv.style.width = "auto";
         var autoWidth = tabDiv.offsetWidth - 10;
         if (oldWidth > autoWidth)
            tabDiv.style.width = oldWidth + "px";
      }

      pxIndex = tabDiv.style.height.indexOf("px");
      if (pxIndex > 0)
      {
         // Use auto if old width is too small.
         var oldHeight = tabDiv.style.height.substring(0, pxIndex);
         tabDiv.style.height = "auto";
         var autoHeight = tabDiv.offsetHeight - 10;
         if (oldHeight > autoHeight)
            tabDiv.style.height = oldHeight + "px";
      }
   }
}

//-----------------
// PRIVATE
XUIPropertyPagesControl.prototype.activateTab = function(tabId)
{
   //alert(tabId);
   var eid = this.eid;

   var tPropPage = document.getElementById(eid);

   var tTabCells = document.getElementById(eid+'PropTabs').rows[0].cells;
   var tTabOnElem = null;

   for (var i = 0; i != tTabCells.length; ++i)
   {
      if (tTabCells[i].className == 'SAWPropPgTabSpacer' || (tTabCells[i].tabDisabled == true))
         continue;

      if (tTabCells[i].id != (eid+tabId))
      {
         tTabCells[i].className = 'SAWPropPgTabCell';
         tTabCells[i].firstChild.firstChild.className = 'SAWPropPgTabOff';
      }
      else
      {
         tTabCells[i].className = 'SAWPropPgTabCell';
         tTabCells[i].firstChild.firstChild.className = 'SAWPropPgTabOn';
         tTabOnElem = tTabCells[i].firstChild.firstChild;
      }
   }

   var tActiveDiv = null;

   for (var i = tPropPage.rows[1].cells[0].firstChild; i != null; i = i.nextSibling)
   {
      if ((i.nodeName != 'DIV') || (i.tabDisabled == true))
         continue;

      if (i.id != (eid + tabId + 'Div'))
      {
         i.style.display = 'block';
      }
      else if (i.id == (eid + tabId + 'Div'))
      {
         i.style.display = 'block';
         tActiveDiv = i;
      }
   }

   tPropPage.lastTab = tabId;

   if ((tActiveDiv != null) && (tActiveDiv.onDisplay != null))
      tActiveDiv.onDisplay(tActiveDiv.onDisplayContext);

   var nMaxHeight = 0;
   var nMaxWidth = 0;
   for (var i = tPropPage.rows[1].cells[0].firstChild; i != null; i = i.nextSibling)
   {
      if ((i.nodeName != 'DIV') || (i.tabDisabled == true))
         continue;

      i.style.display = "block";
      if (is_ie && !is_ie7up)
      {
         i.style.height = "1px";
         i.style.width = "auto";
      }
      else
      {
         i.style.height = "auto";
         i.style.width = "auto";
      }
      nMaxHeight = nMaxHeight < i.offsetHeight ? i.offsetHeight : nMaxHeight-10;
      nMaxWidth = nMaxWidth < i.offsetWidth ? i.offsetWidth : nMaxWidth-10;

      if (i.id != (eid + tabId + 'Div'))
         i.style.display = 'none';
   }

   if (tActiveDiv.offsetHeight < nMaxHeight)
      tActiveDiv.style.height = nMaxHeight + "px";
   if (tActiveDiv.offsetWidth < nMaxWidth)
      tActiveDiv.style.width = nMaxWidth + "px";

   // CR 12-1ERUTIH: IE doesn't always re-layout the relatively-positioned
   // tab cell after the dialog is resized.
   if (tTabOnElem != null)
      tTabOnElem.className = 'SAWPropPgTabOn';

   if (this.callBackEditor != null)
   {
      if (this.callBackEditor.onTabActivate != null)
      {
         if (this[tabId] == null)
         {
            this.callBackEditor.onTabActivate(tabId);
            this[tabId] = true;
         }
      }
   }
}


//-----------------
// PRIVATE
XUIPropertyPagesControl.prototype.disableTabImpl = function(nTabIndex, bDisable)
{
	if (bDisable == null)
		bDisable = true;
		
	var sTabId = this.eid+'tab'+nTabIndex;
	
	var tTabCell = document.getElementById(sTabId);
	
	if (tTabCell == null || (tTabCell.tabDisabled == bDisable))
		return;
		
	var tSpacer = tTabCell.previousSibling;
	while (tSpacer != null && tSpacer.nodeName != 'TD')
		tSpacer = tSpacer.previousSibling;
		
	var sStyle = (bDisable ? 'none' : 'block');

	tTabCell.tabDisabled = bDisable;
	tTabCell.style.display = sStyle;
	var t = tTabCell.firstChild;
	while (t != null)
	{
		//t.style.display = sStyle;
		if (t.className == 'SAWPropPgTabOn')
		{
			t.style.position = (bDisable ? 'static' : 'relative');
			t.style.top = (bDisable ? 'auto' : '1px');
			break;
		}
		t = t.nextSibling;
	}
	
	tSpacer.tabDisabled = bDisable;
	tSpacer.style.display = sStyle;
	
	var tDiv = document.getElementById(sTabId+'Div');
	
	if (tDiv == null)
		return;
		
	tDiv.tabDisabled = bDisable;
	tDiv.style.display = sStyle;
}

//-----------------
// PRIVATE
XUIPropertyPagesControl.onActivateTab = function(eid,tabId)
{
   document.getElementById(eid).propPage.activateTab(tabId);
}

//-----------------
XUIPropertyPagesControl.prototype.setOnActivateTabCallBack = function(tEditor)
{
   this.callBackEditor = tEditor;
}

///////////////////////////////////////////////////////////////////////////////

//-------------------
// Get a unique column ID for a new column in a report
XUIGetUniqueColumnID = function(tReportElement, nNext)
{
   XUICheckNodeName("XUIGetUniqueColumnID", tReportElement, "saw:report");

   if (nNext == null)
      nNext = 1;

   var sTry = "c" + nNext;
   while (tReportElement.selectSingleNode('//saw:column[@columnID="' + sTry + '"]') != null)
      sTry = "c" + ++nNext;

   return sTry;
}

///////////////////////////////////////////////
// framework for modal and non-modal dialog
//////////////////////////////////////////////

saw.addEventListener(document, 'mousedown', ddInit);
saw.addEventListener(document, 'keypress', captureKey);

var isHot=false;
var activeLayer="";
var activeDiv = null;
var bActiveDivIsCloseable = false;
var topLayer=0;
var maxTopLayer=0;
var ddEnabled=false;
var modalDialogEventListeners = new Object;

function addModalDialogOpenedEventListener(fFunc, tCaller)
{
   if (!modalDialogEventListeners.openEventListeners)
      modalDialogEventListeners.openEventListeners = new Array;

   modalDialogEventListeners.openEventListeners.push({functionPointer : fFunc, thisContext : tCaller});
}

function addModalDialogClosedEventListener(fFunc, tCaller)
{
   if (!modalDialogEventListeners.closeEventListeners)
      modalDialogEventListeners.closeEventListeners = new Array;

   modalDialogEventListeners.closeEventListeners.push({functionPointer : fFunc, thisContext : tCaller});
}

function ddMouseup(event)
{
   if(ddEnabled)
   {
      ddEnabled=false;

      saw.removeEventListener(document, 'mousemove', ddMove);
      saw.removeEventListener(document, 'mouseup', ddMouseup);

      var theDiv = getActiveDiv();
      if (!theDiv)
         return;
      saw.showSelects(theDiv);
      saw.hideSelects(theDiv);

      if (is_nav)
      {
         saw.showCharts(theDiv);
         saw.hideCharts(theDiv);
      }
   }
}

function getDiv(divName){
   var theDiv = document.getElementById(divName);
   if (theDiv==null)
   {
      alert("error! Failed to find div obj by name (" + divName + ")");
   }
   return theDiv;
}

function getActiveDiv(){
   if (activeLayer=="")
   {
      alert("error! No active layer yet");
   }
   return getDiv(activeLayer);
}

function getTopDiv(){
   var aDivs = document.getElementsByTagName("div")
   var max = 0;
   var maxDiv;
   for (id = 0; id != aDivs.length; ++id)
   {
      if(aDivs[id].style.display != "none" && parseInt(aDivs[id].style.zIndex) > max)
      {
         max = parseInt(aDivs[id].style.zIndex);
         maxDiv = aDivs[id];
      }
   }
   return maxDiv;
}

function ddInit(event){
   hotItem = saw.getEventTarget(event);

   while (hotItem && hotItem.getAttribute && (hotItem.getAttribute("id") == null || hotItem.getAttribute("id")!="titleBar") && hotItem.tagName!="BODY")
   {
      hotItem = hotItem.parentNode;
      if (!hotItem || !hotItem.getAttribute)
         break;
   }

  
   if (hotItem && hotItem.getAttribute && hotItem.getAttribute("id")=="titleBar")
   {
      offsetx = event.clientX;
      offsety = event.clientY;
      var theDiv = getActiveDiv();
      if (!theDiv)
         return;
      
      nowX=parseInt(saw.isRToL() ? theDiv.style.right : theDiv.style.left);
      nowY=parseInt(theDiv.style.top);

      saw.addEventListener(document, 'mouseup', ddMouseup);
      ddEnabled=true;
      saw.addEventListener(document,'mousemove', ddMove);
      saw.hideSelects(theDiv);
      if (is_nav)
         saw.hideCharts(theDiv);
   }
}

function ddMove(event)
{
   if (!ddEnabled) return;
   var theDiv = getActiveDiv();
   if (!theDiv)
      return false;
   
   if(saw.isRToL())
   {
      var newRight = nowX + offsetx - event.clientX;
      if(is_nav && newRight >= document.documentElement.clientWidth - 5)
         return false;

      theDiv.style.right = newRight + "px";
   } 
   else
      theDiv.style.left = nowX + event.clientX - offsetx + "px";
      
   theDiv.style.top = nowY + event.clientY-offsety + "px";
   
   saw.hideSelects(theDiv);

   return false;
}

function hideDialog(divName, bModaless)
{
   theDiv = getDiv(divName);
   if (!theDiv)
      return;

   //if(theDiv.style.display=="none") return;
   if(!bModaless)
   {
      var s = theDiv.style.zIndex - 1;
      theInvisibleDiv = getDiv("invisibleLayer" + s);
      if (!theInvisibleDiv)
         return;
      document.body.style.height = theInvisibleDiv.oldBodyHeight;
      theInvisibleDiv.parentNode.removeChild(theInvisibleDiv);
      
      saw.removeEventListener(window, "resize", adjustInvisibleLayerSize);
      saw.removeEventListener(window, "scroll", scrollInvisiableLayer); //Removing Scroll listener
      
      var preInvisibleDiv = findPreviousInvisibleLayer(s);
      if (preInvisibleDiv)
      {
         preInvisibleDiv.className = 'OpaqueLayer';
         
         adjustInvisibleLayerSize(null, preInvisibleDiv);
         saw.addEventListener(window, "resize", adjustInvisibleLayerSize, preInvisibleDiv);
         saw.addEventListener(window, "scroll", scrollInvisiableLayer,preInvisibleDiv);
      }

      if(topLayer >= maxTopLayer)
         topLayer -= 1;
   }

   if(topLayer >= maxTopLayer)
      topLayer -= 1;

   theDiv.style.display="none";
   saw.preventMainBarJump();
   activeDiv = null;
   bActiveDivIsCloseable = false;  

   var dlgEvtListeners = modalDialogEventListeners.closeEventListeners;
   if(dlgEvtListeners)
   {
      for (var i = 0; i < dlgEvtListeners.length; i++)
      {
         dlgEvtListeners[i].functionPointer.call(dlgEvtListeners[i].thisContext);
      }
   }
}

function showDialog(divName, eid, bModal, bAutoCloseable)
{
   var theDiv = getDiv(divName);
   if (!theDiv)
      return;
   // do nothing if already show
   // if (theDiv.style.display=="") return;

   // take focus off of link/button that called dialog
   // also could be useful for Section 508
   var tTitleLink = document.getElementById(divName + "TitleLink");
   if (tTitleLink)
   {
      tTitleLink.focus();
      tTitleLink.blur();
      if (eid)
      {
         var tEditor = XUIPanel.getEditor(eid);
         if (tEditor)
            tEditor.focus();
      }
   }
   
   if (activeDiv == null || activeDiv.id != theDiv.id)
   {
       if(bModal)
       {
          topLayer += 1;
          addInvisibleLayer(topLayer, theDiv);      
       }
       //add a layer
       topLayer += 1;
       theDiv.style.zIndex = topLayer;

       //find maxtoplayer;
       if(topLayer > maxTopLayer) maxTopLayer = topLayer;
   }
   
   // show the dialog
   theDiv.style.display="";
   saw.preventMainBarJump();
   activeDiv = theDiv;   
   bActiveDivIsCloseable = (bAutoCloseable == true?true:false);
   
   //set the width/height of the shadow
   adjustDialogDropShadowSize(theDiv);
   
   var dlgEvtListeners = modalDialogEventListeners.openEventListeners;
   if(dlgEvtListeners)
   {
      for (var i = 0; i < dlgEvtListeners.length; i++)
      {
         dlgEvtListeners[i].functionPointer.call(dlgEvtListeners[i].thisContext);
      }
   }
}


//fix the width/height of the shadow (IE doesn't compute cell width/height correctly here)
function adjustDialogDropShadowSize(theDiv)
{
   if (is_ie || is_mac)
   {
      try {
         var tShadowTable = saw.getFirstChildElement(theDiv);
         
         //saw.fixDropShowdowStyle(tShadowTable);
                 
         // shadow offset
         tShadowTable.rows[0].cells[1].style.height = "2px";
         tShadowTable.rows[2].cells[0].style.width = "2px";
         //shadow width/height
         var height = theDiv.clientHeight - tShadowTable.rows[2].cells[2].clientHeight * 2;
         var width = theDiv.clientWidth - tShadowTable.rows[2].cells[2].clientWidth * 2;
         // the size of the dialog changes (e.g. changes to anther Tab).
         // If we set the size of the shadow to be the size of the dialog, when the dialog becomes smaller, the shadow becomes too big.
         // So we set the size of the shadow to be a small value and let IE expand it.
         if (height > 150)
            height = 150;         
         tShadowTable.rows[1].cells[0].style.height = height + 'px';
         if (width > 150)
            width = 150;         
         tShadowTable.rows[2].cells[1].style.width = width + 'px';
      }
      catch (x)
      {}
   }
}

function addInvisibleLayer(z, e)
{
   var NewDiv = document.createElement("div");

   document.body.appendChild(NewDiv);
   NewDiv.setAttribute("id", "invisibleLayer" + z);
   NewDiv.oldBodyHeight = document.body.style.height;

   //"width:100%" won't work properly when the page is larger than size of browser (there are scroll bars)
   NewDiv.innerHTML = "<table border='0px' style='background-color:transparent;left:0px;top:0px;' ><tr ><td ><div >&nbsp;</div></td></tr></table>";
   NewDiv.style.position = "absolute";
   NewDiv.style.width = saw.getClientWidth() + 'px';
   NewDiv.style.height = saw.getClientHeight() + 'px';
   NewDiv.style.top = "0px";
   NewDiv.style.left = "0px";
   NewDiv.style.zIndex = z;
      
   NewDiv.className = 'OpaqueLayer';
   var preInvisibleDiv = findPreviousInvisibleLayer(z);
   if (preInvisibleDiv)
   {
      preInvisibleDiv.className = 'TransparentLayer';
      saw.removeEventListener(window, "resize", adjustInvisibleLayerSize);
      saw.removeEventListener(window, "scroll", scrollInvisiableLayer);
   }
   
   saw.addEventListener(window, "resize", adjustInvisibleLayerSize, NewDiv);
   saw.addEventListener(window, "scroll", scrollInvisiableLayer, NewDiv);
}
function scrollInvisiableLayer(evt,div)
{
    div.style.top  = saw.getDocumentScrollTop()+'px';
    div.style.left  = saw.getDocumentScrollLeft()+'px';
}
function adjustInvisibleLayerSize(evt, div)
{
   div.style.width = "auto";
   div.style.height = "auto";
   div.style.width = saw.getClientWidth() + 'px';
   div.style.height = saw.getClientHeight() + 'px';
}

// z is index of current InvisibleLayer
function findPreviousInvisibleLayer(z)
{
   var zIndex = z - 2;
   if (zIndex >= 0)
   {
      var preInvisibleDiv = document.getElementById("invisibleLayer" + zIndex);
      while(zIndex > 0 && preInvisibleDiv == null)
      {
         zIndex -= 1;
         preInvisibleDiv = document.getElementById("invisibleLayer" + zIndex);
      }
   }

   return preInvisibleDiv;
}

function setHot(layerName)
{
   // if draging.. do nothing..
   if (ddEnabled) return;

   isHot=true;
   activeLayer=layerName;
}

function setCold()
{
   isHot=false;
   
}

function captureKey(event)
{
   var CR = 13; // Carriage Return
   var escape = 27;

   charCode = event.keyCode;

   if (charCode == CR || charCode == escape)
   {
      //if(obj == null)
      var obj = getTopDiv();

      // if no top div
      if(obj != null && obj.getAttribute("id") && obj.captureKey != "false")
      {
         // If i'm on a button, don't do anything - just follow the link
         if ((charCode == CR) && (saw.getEventTarget(event).nodeName != 'A') && (saw.getEventTarget(event).nodeName != 'TEXTAREA'))
            return XUIDialog.ok(getEID(obj.getAttribute("id")));
         else if (charCode == escape)
            return XUIDialog.cancel(getEID(obj.getAttribute("id")), event);
      }
   }

}

function getEID(objID)
{
    return objID.substr(0, objID.length-3);
}


//-------------------
//-------------------
// Common functions for applying masked defaults.  Used by dashboards and answers.

//-------------------
// This method appends attributes if they exist in the mask.  Ignores signature
// attribute.
XUIAddMaskedAttributes = function(tTarget, tSource, tMask)
{
   var tAttrs = tSource.selectNodes("@*");
   for (var ia = 0; ia < tAttrs.length; ++ia)
   {
      // verify presence in mask and add
      var sName = tAttrs[ia].nodeName;
      if ((sName != "signature") &&
          ((tSource.nodeName == "displayFormat") || (tMask.selectSingleNode("@" + sName) != null)))
      {
//alert('Defaulting Attribute: ' + sName);
         if (sName == "type")
            XUISetXsiType(tTarget, saw.xml.kSawNamespace, tAttrs[ia].value);
         else
            tTarget.setAttributeNode(tAttrs[ia].cloneNode(true));
      }
   }
}

//-------------------
// This method appends elements if they exist in the mask.
XUIAddMaskedElements = function(tTarget, tSource, tMask)
{
   var tElements = tSource.selectNodes("*");
   for (var ie = 0; ie < tElements.length; ++ie)
   {
      var sName = tElements[ie].nodeName;

      var tMaskElement = tMask.selectSingleNode(sName);
      if (tMaskElement != null)
      {
         // Check for special handling of caption elements
         if (sName == 'caption')
         {
            var tCap = new XUICaptionParent(tTarget);
            tCap.setCaptionText(XUIGetElementText(tElements[ie]));
         }
         else
         {
            var tNewElement = XUIForceSingleNode(tTarget, saw.xml.kSawNamespace, sName);
            XUIAddMaskedAttributes(tNewElement, tElements[ie], tMaskElement);

            // Recurse
            XUIAddMaskedElements(tNewElement, tElements[ie], tMaskElement);
         }
      }
   }
}

//-------------------
// Restrict field entry to a specified number of characters
function restrictLength(field, maxlimit)
{
   if (field.value.length > maxlimit)
   {
      field.value = field.value.substring(0, maxlimit);
   }
}

XUIIsAllCaptionsInElementTextEncoded = function(viewElem,captionsXPath)
{   
   if (captionsXPath == 'undefined' || captionsXPath == null )
      captionsXPath = './/saw:caption';
   
   var vCaptions = viewElem.selectNodes(captionsXPath);

   for (var i=0; i<vCaptions .length; i++)
   {
      var fmt  = vCaptions[i].getAttribute("fmt");
      if (fmt == 'html')
         return false;
   }
   return true;  
}
