////////////////////////////////////////////////////////////////////////////
//  File:            u_page.js
//  Description:     This file conatains the page and row classes. This Page
//                   class is used to create dynamic pages. It contain
//                   methods to create various inputs with automatic data
//                   validation. The Row class contains methods for creating
//                   the rows on the page.
//  Original Author: Jonathan J. Smith (jonathan.smith@polycom.com)
////////////////////////////////////////////////////////////////////////////

var kDefaultFormName = "settings"
var kDefalutFormMethod = "post"
var kDefalutEncType = ""
var kDefalutFormAccept = ""
var kAttributeSeperator = "?"
var kAttValueSeperator = "|"
var kDependentRows = "dependentRows"
var textNodeCount = 0 // We use this to give each text node a unique id

var EXCLUDE_INPUT = "_exclude"
var FIELD_ORDER   = "_fieldorder"

// This is the page object. There is always one and only one
// page so it is created here. There are other ways to create
// a singleton in JavaScript but they have there own disadvantages.
page = new Page ()

// The Page class
function Page ()
{ 
  this.pageName = null
  this.formName = null
  this.groupName = null
  this.action = ""
  this.style = "configData"
  this.currentRow = 0
  this.tabed = 0
  this.onhide = null
  this.onshow = null
  this.pageTableBody = null
  this.dataTableBody = null
  this.bootOnAnyChanges = false
  this.bootOnSomeChanges = false
  this.rows = new Array ()
  this.useColumns = false
  this.dataTableCount = 0
  this.currentIndent = 0
  this.errorMsg = ""
  this.autoSubmit = false  
}

//////////////////////////////////////////////////////////////////////
//  Name:        ForceSubmitOnChange
//  Description: Any changes made in the page will be instantly 
//               submitted to the server.
//////////////////////////////////////////////////////////////////////

Page.prototype.ForceSubmitOnChange = function ()
{
  this.autoSubmit = true
}

//////////////////////////////////////////////////////////////////////
//  Name:        ForceBootOnAnyChange
//  Description: Set the flag that this page will cause a reboot on
//               any change.
//////////////////////////////////////////////////////////////////////

Page.prototype.ForceBootOnAnyChange = function ()
{
  this.bootOnAnyChanges = true
}

//////////////////////////////////////////////////////////////////////
//  Name:        IsRebootNeeded
//  Description: Check to see if any thing changed that would cause
//               a reboot
//////////////////////////////////////////////////////////////////////

Page.prototype.IsRebootNeeded = function ()
{
  if (isOOB) return false
 
  if (this.bootOnAnyChanges || this.bootOnSomeChanges)
  {
    var inputType
    
    for (inputType in kInputTypes)
    {
      if (CheckListForReboot (
        document.getElementsByTagName(kInputTypes[inputType])))
        return true
    }
  }
  return false
}

//////////////////////////////////////////////////////////////////////
//  Name:        OnClickBack
//  Description: Going back
//////////////////////////////////////////////////////////////////////

Page.prototype.OnClickBack = function (nextPage, onSubmit, form)
{
  goingBack = true
  this.OnClickBackNext (nextPage, onSubmit, form)
}

//////////////////////////////////////////////////////////////////////
//  Name:        OnClickNext
//  Description: Going back
//////////////////////////////////////////////////////////////////////

Page.prototype.OnClickNext = function (nextPage, onSubmit, form)
{
  goingBack = false
  this.OnClickBackNext (nextPage, onSubmit, form)
}

//////////////////////////////////////////////////////////////////////
//  Name:        OnClickBackNext
//  Description: if we are OOB then and we are not on the last screen
//               we need to submit when clicking back or next
//////////////////////////////////////////////////////////////////////

Page.prototype.OnClickBackNext = function (nextPage, onSubmit, form)
{
  if (isOOB)
  {
    SetHtmFile (nextPage)
    this.CheckAndSubmitForm (onSubmit, form)
  }
  else
  {
    LoadContent (nextPage)
  }
}

//////////////////////////////////////////////////////////////////////
//  Name:        CheckAndSubmitForm
//  Description: Verify that all of the page fields contain valid
//               data and submit the form.
//////////////////////////////////////////////////////////////////////

Page.prototype.CheckAndSubmitForm = function (onSubmit, form)
{
  // If the page contains a content frame then we are viewing the
  // inside the frame on the main page and we need to call the
  // submit function from within that frame.
  // alert ("page.CheckAndSubmitForm")
  var cFrame = document.getElementById ("contentFrame")
  if (cFrame) 
    return cFrame.contentWindow.page.CheckAndSubmitForm (onSubmit, form)

  if (!form) form = this.formName
  if (VerifyData ())
  {
    // If the system needs to be rebooted prompt the user to make sure
    // they want to submit the page
    // alert ("onSubmit = \"" + onSubmit + "\"");
    if (((onSubmit == null || onSubmit == "" ) ? true : eval (onSubmit)))
    {
      if (this.IsRebootNeeded ()) 
      {
        if (confirm (APPLICATION_MUST_BE_RESTARTED))
        {
          // If we need to reboot and the page has an action than that
          // action will have to force the reboot.
          //if (this.GetAction (form) == "") this.SetAction (rebootAction, form);
          //SetHtmFile ("a_rebootmeter.htm")
          showPopWin('u_processing.htm?message=PLEWAIWHISYSRES&pollstatus=true', 400, 130, null, false)          
        }
        else
        {
           return false;
        }
      }

      this.Submit (form)
      return true;  // For completeness
    }
  }
  return false;
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddBodyEnd
//  Description: Add the back, next and update buttons and a function
//               to be executed on submitting of the page.
//
//  backPage     = The url to go to when the back button is clicked.
//  nextPage     = The url to go to when the next button is clicked.
//  showUpdate   = Indecates wether or not we want to show the update
//                 button. (default = true)
//  backPage     = The url to go to when the back button is clicked.
//////////////////////////////////////////////////////////////////////

Page.prototype.AddBodyEnd = function (backPage, nextPage, showUpdate, onSubmit)
{
  var newRow
  
  if (this.bootOnAnyChanges) this.AddFootnoteText (CHANGES_WILL_REBOOT)
  if (this.bootOnSomeChanges) this.AddFootnoteText (CHANGES_RESTART_WEB)
  if (this.autoSubmit) this.AddFootnoteText (AUTO_SUBMIT_WEB)

  if (document.getElementById (NOERROR_PAGE) == null)
    this.AddHiddenInput (NOERROR_PAGE, ((nextPage) ? nextPage :
      GetCurrentPageName ()))
  
  // Register for changes to dependent objects
  for (rowIndex in this.rows)
  {
    var newRow = this.rows[rowIndex]
    this.RegisterForChanges (newRow.dependentObjects, newRow.rowNumber)
  }
  
  // Create all of the rows
  for (rowIndex in this.rows)
  {
    var newRow = this.rows[rowIndex]
    var newRowPtr = newRow.CreateRow ()

    if (newRowPtr != null)
    {
      newRow.dataTable.appendChild (newRowPtr)
      if (newRow.oncreationof != null && newRow.oncreationof != "")
        eval (newRow.oncreationof)
    }
  }
  
  this.AddUpdateNextButtons (backPage, nextPage, showUpdate, onSubmit)
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddBodyStart
//  Description: Set the page, form and group name. Create the main
//               form and table.
//
//  pageName     = The name of the page.
//  formName     = The name of the form.
//  groupName    = The name of the group. This should match the
//                 embedded group.
//  action       = The action to take on submit.
//  method       = The form submit method (default = "post").
//  encType      = The form encryption type.
//  accept       = The form accept value
//  style        = The CSS style for the main table (default =
//                 "configData")
//////////////////////////////////////////////////////////////////////

Page.prototype.AddBodyStart = function (pageName, formName, groupName,
  action, method, encType, accept, style)
{
  this.pageName = pageName
  this.groupName = groupName
  if (style) this.style = style

  this.dBody = document.body
  this.endOfPage = this.dBody.appendChild (
    CreateElement ('<table id="configData" class="'+this.style+'">'))
  this.endOfPage = this.endOfPage.appendChild (CreateElement ('<tbody>'))
  this.pageTableBody = this.endOfPage
  // If we are loading this page inside the menus the page title will row
  // will already be there.
  if (!parent.document.getElementById ("pageTitle"))
  {
    var newElement = this.endOfPage.appendChild (
      CreateElement ('<tr id="headerRow">'))
    newElement = newElement.appendChild (CreateElement ('<td>'))
    newElement.appendChild (this.CreateHeaderTable ())
  }
  
  this.pageName && this.AddPageLabel (this.pageName)
  
  this.pageTableBody = this.pageTableBody.appendChild (CreateElement ('<tr>'))
  this.pageTableBody = this.pageTableBody.appendChild (CreateElement ('<td>'))
  
  if (formName) this.AddForm (formName, method, action, encType, accept)
  this.AddDataTableStart ()                    
  this.AddGroup ()
  this.AddRow ("tabed=2", 'name=notificationrow', 'columns=2',
            'style=errormsg',
            this.AddTextNode (this.errorMsg, "notification")) 
  if (this.bootOnAnyChanges) this.AddFootnoteText (CHANGES_WILL_REBOOT)
  if (this.autoSubmit) this.AddFootnoteText (AUTO_SUBMIT_WEB)
}

var kErrorMessage = 0
var kStatusMessage = 1

//////////////////////////////////////////////////////////////////////
//  Name:        SetErrorMsg
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.SetErrorMsg = function (sMessage)
{
  this.errorMsg = sMessage
}

//////////////////////////////////////////////////////////////////////
//  Name:        ShowStatusMsg
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.ShowStatusMsg = function (sMessage)
{
  this.ShowMsg (sMessage, kStatusMessage)
}

//////////////////////////////////////////////////////////////////////
//  Name:        ShowErrorMsg
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.ShowErrorMsg = function (sMessage)
{
  this.ShowMsg (sMessage, kErrorMessage)
}

//////////////////////////////////////////////////////////////////////
//  Name:        ShowMsg
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.ShowMsg = function (sMessage, type)
{
  var noteObject = document.getElementById("notification")
  this.errorMsg = sMessage
  noteObject.innerHTML = sMessage
  noteObject.className = (type == kErrorMessage) ? "errormsg" : "statusmsg"
}

//////////////////////////////////////////////////////////////////////
//  Name:        ClearMsg
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.ClearMsg = function ()
{
  this.ShowMsg ("")
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddCheckBox
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddCheckBox = function (name, value, onChange,
  forceNavUpdate, rebootOnChange, isReadOnly, condition)
{
  var checkBox
  var checkBoxHelper
  var checked = value == "True"
  var newElement = document.createDocumentFragment()
  var checkBoxName = name + "checkbox"
  onChange = (!onChange) ? "" : onChange + ";"

  if (isReadOnly == null) isReadOnly = false
  onClick = 'ClickCheckBoxImage(this);'
  onChange += 'UpdateDependentRows (document.getElementById(\''+name+'\'));'
  if (forceNavUpdate) onClick += 'UpdateNavReloadCB(this);'
  // Create the checkbox Image
  checkBox = CreateElement ('<img onclick="'+onClick+'" '+
//    'src="'+("checkbox" + value + ".png")+'" ' +
//    'disabled="'+isReadOnly+'"' +
//    'helper="'+name+'"' +
    'name="'+checkBoxName+'" id="'+checkBoxName+'">')
  checkBox.setAttribute ("onchange", onChange)
  checkBox.setAttribute ("disabled", isReadOnly)
  checkBox.setAttribute ("helper", name)
  SetImageValue (checkBox, checked)
  checkBox.src = GetCheckBoxImageName (checkBox)
  this.SetCommonAttributes (checkBox, rebootOnChange, condition);
  newElement.appendChild (checkBox);
  // Create the helper
  checkBoxHelper = CreateElement ('<input type="hidden" id="'+name+
    '" name="'+name+'" value="'+value+'">');
  this.SetCommonAttributes (checkBoxHelper, rebootOnChange, condition);
  newElement.appendChild (checkBoxHelper);
  return newElement;
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddDataTableStart
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddDataTableStart = function (useColumns)
{
  this.dataTableCount++
  this.useColumns = (useColumns) ? useColumns : false
  this.dataTableBody = this.pageTableBody.appendChild (CreateElement
    ('<table class="dataTable" id="dataTable'+this.dataTableCount+
    '" border="0" cellpadding="0" cellspacing="2">'))
  this.dataTableBody = this.dataTableBody.appendChild (
    CreateElement('<tbody id="dataTableBody'+this.dataTableCount+'">'))
  
  return "dataTableBody"+this.dataTableCount
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddDoubleByteEditBox
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddDoubleByteEditBox = function (name, value, length, size,
  onChange, isRequired, requiredText, rebootOnChange, condition)
{
  return this.AddEditBox (name, value, length, size, 'ValidateDoubleByte',
    onChange, isRequired, requiredText, rebootOnChange, condition)
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddEditBox
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddEditBox = function (name, value, length, size, dataValidation, 
  onChange, isRequired, requiredText, rebootOnChange, condition, parameters)
{
  return this.CreateInput ("text", name, value, length, size, dataValidation,
    onChange, isRequired, requiredText, rebootOnChange, condition, parameters)
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddEmailEditBox
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddEmailEditBox = function (name, value, length, size,
  onChange, isRequired, requiredText, rebootOnChange, condition)
{
//  var validateFunc = 'tmt_RegExpValidator(\''+name+
//    '\',\'%5E%5B%5Cw%5C.=-%5D%2B@%5B%5Cw%5C.-%5D%2B%5C.%5Ba-z%5D%7B2,3%7D$\',INVALID_EMAIL,\'\',\'\');'
  return this.AddEditBox (name, value, length, size, "EmailOnly",
    onChange, isRequired, requiredText, rebootOnChange, condition)
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddFootnoteText
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddFootnoteText = function (textID, rowId)
{
  if (!rowId) rowId = "footnoterow"
  
  this.AddRow ('name='+rowId, 'style=footnote', 'columns=2',
    page.AddTextNode (textID))
}

function args2Array (args, start)
{
  var argsArray = new Array ()
  if (!start) start = 0
  for (var index = start; index < args.length; index++)
  {
    argsArray[argsArray.length] = args[index]
  }
  return argsArray
}

//////////////////////////////////////////////////////////////////////
//  Name:        StartDefaultStyleSection
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.StartDefaultStyleSection = function (rowId, label)
{
  var args = new Array ('name='+rowId,
    'tabed='+this.currentIndent++,
    page.AddTextNode (label))
  
  this.CreateRow (args.concat (args2Array (arguments, 2)))
}
//////////////////////////////////////////////////////////////////////
//  Name:        StartSection
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.StartSection = function (rowId, label)
{
  var args = new Array ('name='+rowId,
    'labelstyle=label',
    'datastyle=labeldata',
    'tabed='+this.currentIndent++,
    page.AddTextNode (label))

  this.CreateRow (args.concat (args2Array (arguments, 2)))
}

//////////////////////////////////////////////////////////////////////
//  Name:        EndSection
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.EndSection = function ()
{
  this.currentIndent--
}
//////////////////////////////////////////////////////////////////////
//  Name:        AddWebLanguageSelect
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddWebLanguageSelect = function  (languages, wc1, wc2, wc3)
{
  if(!languages)
  	languages = webLanguags;

  if (wc1 && wc1 != "none")
  {
    languages += "?" + page.GetAbbrevforLanguage(wc1) + "|" + page.GetLocalizedLanguage(wc1)
    if (wc2 && wc2 != "none") 
    {
      languages += "?" + page.GetAbbrevforLanguage(wc2) + "|" + page.GetLocalizedLanguage(wc2)
      if (wc3 && wc3 != "none")
        languages += "?" + page.GetAbbrevforLanguage(wc3) + "|" + page.GetLocalizedLanguage(wc3)
    }
  }
  
  return this.AddRadioList ("web_language", languages, GetLanguage (),
    "MM_OnLanguageChange(this.value);")
}

////////////////////////////////////////////////////////////////////////////////
//  Name:        GetLocalizedLanguage
//  Description: Description
////////////////////////////////////////////////////////////////////////////////

Page.prototype.GetLocalizedLanguage = function (value)
{
  switch(value)
  {
        case "Finnish": return "Suomi";
        case "Afrikaans": return "Afrikaans";
        case "Albanian": return "Albanian";
        case "Basque": return "Basque";
        case "Bulgarian": return "Bulgarian";
        case "Catalan": return "Catalan";
        case "Croatian": return "Croatian";
        case "Czech": return "Czech";
        case "Danish": return "Danish";
        case "Dutch": return "Dutch";
        case "Estonian": return "Estonian";
        case "Faeroese": return "Faeroese";
        case "Greek": return "Greek";
        case "Icelandic": return "Icelandic";
        case "Indonesian": return "Indonesian";
        case "Latvian": return "Latvian";
        case "Lithuanian": return "Lithuanian";
        case "Macedonian": return "Macedonian";
        case "Romanian": return "Romanian";
        case "Serbian": return "Serbian";
        case "Slovak": return "Slovak";
        case "Slovenian": return "Slovenian";
        case "Swahili": return "Swahili";
        case "Swedish": return "Swedish";
        case "Turkish": return "Turkish";
        case "Ukrainian": return "Ukrainian";
        case "Persian": return "Persian";
        case "Urdu": return "Urdu";
        case "Sindhi": return "Sindhi";
        case "Kurdish": return "Kurdish";
        case "Uighur": return "Uighur";
    default: return "English";
  }
}

////////////////////////////////////////////////////////////////////////////////
//  Name:        GetAbbrevforLanguage
//  Description: Description
////////////////////////////////////////////////////////////////////////////////

Page.prototype.GetAbbrevforLanguage = function (value)
{
  switch(value)
  {
        case "Finnish": return "FI";
        case "Afrikaans": return "AF";
        case "Albanian": return "SQ";
        case "Basque": return "EU";
        case "Bulgarian": return "BG";
        case "Catalan": return "CA";
        case "Croatian": return "HR";
        case "Czech": return "CS";
        case "Danish": return "DA";
        case "Dutch": return "NL";
        case "Estonian": return "ET";
        case "Faeroese": return "FO";
        case "Greek": return "EL";
        case "Icelandic": return "IS";
        case "Indonesian": return "ID";
        case "Latvian": return "LV";
        case "Lithuanian": return "LT";
        case "Macedonian": return "MK";
        case "Romanian": return "RO";
        case "Serbian": return "SR";
        case "Slovak": return "SK";
        case "Slovenian": return "SL";
        case "Swahili": return "SW";
        case "Swedish": return "SV";
        case "Turkish": return "TR";
        case "Ukrainian": return "UK";
        case "Persian": return "FA";
        case "Urdu": return "UR";
        case "Sindhi": return "SD";
        case "Kurdish": return "KU";
        case "Uighur": return "UG";
    default: return "EN";
  }
}

////////////////////////////////////////////////////////////////////////////////
//  Name:        AddCustomLangSelect
//  Description: Description
////////////////////////////////////////////////////////////////////////////////

Page.prototype.AddCustomLangSelect = function (name, values, wc1, wc2, wc3, currentLang)
{
  var options;
  var sOption;
  var aOption;
  var index;
  var newElement;
  var newOption;
  var text
  var defaultValue = ""
  var isFistLineADup = false
  var selectedIndex = 0
  var choiceFile;
  var onChange;
  
  if (!values) return null
  
  if (wc1 && wc1 != "none")
  {
    values += "?" + wc1;
    if (wc2 && wc2 != "none") 
      {
      values += "?" + wc2;
      if (wc3 && wc3 != "none")
        values += "?" + wc3;
      }
  }
  
   choiceFile = name
   onChange += ";page.UpdateCommonAttributes (this);UpdateDependentRows (this);";
   options = values.split ("?")
   if (options.length == 1 || (options.length == 2 && 
     options[0].split ("|")[0] == options[1].split ("|")[0]))
   {
     return this.AddTextNode (TranslateOption (choiceFile, options[0].split ("|")[0]), name)
   }
   
   newElement = CreateElement ('<select align="absmiddle" id="'+name+'" name="'+name+'" onchange="'+onChange+'">')

   for (index = 0; index < options.length; index++)
   {
     aOption = options[index].split("|")
     newOption = newElement.appendChild (CreateElement('<option value="'+aOption[0]+'">'))
     newOption.text = TranslateOption (choiceFile, aOption[0])
     if ((aOption.length > 1 && aOption[aOption.length-1] == kSelected))
         selectedIndex = index
     if (currentLang && aOption[0] == currentLang)
         selectedIndex = index
     if (index == 0)
     {
       defaultValue = newOption.value
     }
     else
     {
       if (!isFistLineADup) isFistLineADup = newOption.value == defaultValue
     }
   }

   if (isFistLineADup)
   {
     newElement.options[0] = null
     if (selectedIndex != 0) --selectedIndex
   }
 
   newElement.selectedIndex = selectedIndex
  
  this.SetCommonAttributes (newElement, null, null)

  return newElement;
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddForm
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddForm = function (formName, method, action, encType, accept)
{
  var newRow
  var newForm
  
  this.formName = formName
  this.action = (action) ? action : ""
  method = (method) ? method : kDefalutFormMethod
  encType = (encType) ? ' enctype="'+encType+'"' : kDefalutEncType
  accept = (accept) ? ' accept="'+accept+'"' : kDefalutFormAccept

  this.pageTableBody = this.pageTableBody.appendChild (CreateElement
    ('<form id="'+this.formName+'" name="'+this.formName+'" method="'+method+
      '" action="'+this.action+'"'+encType+accept+'>'))
  //this.pageTableBody = this.endOfPage
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddGroup
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddGroup = function ()
{
  if (this.groupName != null && this.groupName != "")
    this.AddHiddenInput ("_groupname", this.groupName)
}


//////////////////////////////////////////////////////////////////////
//  Name:        AddImage
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddImage = function (name, src, args, onClick)
{
  if (args == null) args = ""
  if (onClick == null) onClick = ""
  
  return CreateElement ('<img onclick="'+onClick+'" src="'+
    src+'" name="'+name+'" id="'+name+'" '+args+'>')
}
//////////////////////////////////////////////////////////////////////
//  Name:        AddHiddenInput
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddHiddenInput = function (name, value)
{
  this.dataTableBody.appendChild (
    CreateElement ('<input type="hidden" name="'+name+
      '" id="'+name+'" value="'+value+'">'))
}

//////////////////////////////////////////////////////////////////////
//  Name:        CreateInput
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.CreateInput = function (type, name, value, length, size,
  dataValidation, onChange, isRequired, requiredText, rebootOnChange,
  condition, parameters)
{
  var dataValidationCmds = ""
  var onChangeCmds = ""
  var thisObj = 'document.getElementById(\''+name+'\')'
  var requiredFunc = (isRequired) ? 
    'VerifyNotBlank ('+thisObj+', \''+requiredText+'\')' : ""
  var newElement
  
  if (onChange == null) onChange = ""
  AddToAndList (onChange, "UpdateDependentRows (this)")
  // if the type is range the real type is still input but we
  // need to add paramaters to the validation function 
  if (dataValidation)
  {
    dataValidation += '('+thisObj
    if (parameters && parameters != "")
      dataValidation += ", " + parameters
    dataValidation += ')'
  }
  if (length == null) length = ""
  var style = ""
  if (isNaN (size))
  {
    if (size == "max")
    {
      size = kMaxEditBoxLength
    }
    else
    {
      style = size
      size = ""
    }
  }
  else if (size == null)
  {
    size = Math.min ((length == "") ? "" : length * 1.4,
       kMaxEditBoxLength)
  }
   
  dataValidationCmds = AddToAndList (dataValidationCmds,
    dataValidation, requiredFunc)
  onChangeCmds = AddToAndList (onChangeCmds,
                 "page.UpdateCommonAttributes (this)",
                 "ValidateField (this)", onChange)
  if (onChangeCmds != "") 
    onChangeCmds = "return ("+onChangeCmds+")"
  //alert ("dataValidationCmds = \""+dataValidationCmds+"\"")
    
  newElement =
    CreateElement ('<input name="'+name+'" type="'+type+'" class="'+style+'" id="'+
    name+'" vFunction="'+dataValidationCmds+'" onchange="'+onChangeCmds+
    '" value="'+value+'" size="'+size+'" maxlength="'+length+'">')
  this.SetCommonAttributes (newElement, rebootOnChange, condition)
  return newElement
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddIPEditBox
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddIPEditBox = function (name, value, length,
   size, onChange, isRequired, requiredText, rebootOnChange,
   condition)
{
  return this.AddEditBox (name, value, length, size, "IpOnly",
    onChange, isRequired, requiredText, rebootOnChange, condition)
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddIPv6EditBox
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddIPv6EditBox = function (name, value, length,
   size, onChange, isRequired, requiredText, rebootOnChange,
   condition)
{
  return this.AddEditBox (name, value, length, size, "Ipv6Only",
    onChange, isRequired, requiredText, rebootOnChange, condition)
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddIPv4OrIPv6EditBox
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddIIPv4OrIPv6EditBox = function (name, value, length,
   size, onChange, isRequired, requiredText, rebootOnChange,
   condition)
{
  return this.AddEditBox (name, value, length, size, "Ipv4OrIpv6Only",
    onChange, isRequired, requiredText, rebootOnChange, condition)
}
//////////////////////////////////////////////////////////////////////
//  Name:        AddDialingPrefixEditBox
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddDialingPrefixEditBox = function (name, value, length, size,
  onChange, isRequired, requiredText, rebootOnChange, condition)
{
  return this.AddEditBox (name, value, length, size, "DialingPrefix",
    onChange, isRequired, requiredText, rebootOnChange, condition)
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddIntegersOnlyEditBox
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddIntegersOnlyEditBox = function (name, value, length, size,
  onChange, isRequired, requiredText, rebootOnChange, condition)
{
  return this.AddEditBox (name, value, length, size, "IntegersOnly",
    onChange, isRequired, requiredText, rebootOnChange, condition)
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddNumbersOnlyEditBox
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddNumbersOnlyEditBox = function (name, value, length,
  size, onChange, isRequired, requiredText, rebootOnChange, condition)
{
  return this.AddEditBox (name, value, length, size, "NumbersOnly",
    onChange, isRequired, requiredText, rebootOnChange, condition)
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddRangeEditBox
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddRangeEditBox = function (name, value, start, end, length,
  size, onChange, isRequired, requiredText, rebootOnChange, condition)
{
  return  this.AddEditBox (name, value,
    (!length ? GetNumberOfDigits(end) : length),
    size, "CheckIntRange",
    onChange, isRequired, requiredText, rebootOnChange,
    condition, start + ", " + end)
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddKeyboardOnlyEditBox
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddKeyboardOnlyEditBox = function (name, value, length, size,
  onChange, isRequired, requiredText, rebootOnChange, condition)
{
  return  this.AddEditBox (name, value, length, size, "KeyboardInputOnly",
    onChange, isRequired, requiredText, rebootOnChange, condition)
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddKeypadOnlyEditBox
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddKeypadOnlyEditBox = function (name, value, length, size,
  onChange, isRequired, requiredText, rebootOnChange, condition)
{
  return  this.AddEditBox (name, value, length, size, "KeypadOnly",
    onChange, isRequired, requiredText, rebootOnChange, condition)
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddLink
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddLink = function (link, label, style)
{
  var newElement;
  var newOption;
  if (!style) style = ""

  newElement = CreateElement ('<a class="'+style+'" href="'+link+'">');
  newElement.innerText = label; // TODO: Fix NS
  return newElement;
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddPageLabel
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddPageLabel = function ()
{
  var titleObj = parent.document.getElementById ("pageTitle")
  titleObj.innerHTML = this.pageName;
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddPasswordEditBox
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddPasswordEditBox = function (name, value, length, size, 
  onChange, isRequired, requiredText, rebootOnChange, condition)
{
  return this.CreateInput ("password", name, value, length, size,
    "VerifyPassword", onChange, isRequired, requiredText,
    rebootOnChange, condition)
}

Page.prototype.AddDoubleBytePasswordEditBox = function (name, value, length, size, 
  onChange, isRequired, requiredText, rebootOnChange, condition)
{
  return this.CreateInput ("password", name, value, length, size,
    "ValidateDoubleByte", onChange, isRequired, requiredText,
    rebootOnChange, condition)
}


//////////////////////////////////////////////////////////////////////
//  Name:        AddPasswordConfirmEditBox
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddPasswordConfirmEditBox = function (name, newName, passwordfile, errorMsg, value, length, size, 
  onChange, isRequired, requiredText, rebootOnChange, condition)
{
  var editBox = this.CreateInput ("password", name, value, length, size,
    "ConfirmPassword", onChange, isRequired, requiredText,
    rebootOnChange, condition)
  editBox.setAttribute ("newPasswordId", newName)
  editBox.setAttribute ("message", errorMsg)
  editBox.setAttribute("passwordfile", passwordfile)

  return editBox
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddDoubleBytePasswordConfirmEditBox
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddDoubleBytePasswordConfirmEditBox = function (name, newName, passwordfile, errorMsg, value, length, size, 
  onChange, isRequired, requiredText, rebootOnChange, condition)
{
  var editBox = this.CreateInput ("password", name, value, length, size,
    "ConfirmDoubleBytePassword", onChange, isRequired, requiredText,
    rebootOnChange, condition)
  editBox.setAttribute ("newPasswordId", newName)
  editBox.setAttribute ("message", errorMsg)
  editBox.setAttribute("passwordfile", passwordfile)

  return editBox
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddISDNNumberEditBox
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddISDNNumberEditBox = function (name, value, length, size,
  onChange, isRequired, requiredText, rebootOnChange, condition)
{
  return this.AddEditBox (name, value, length, size, 'CheckISDNInput',
    onChange, isRequired, requiredText, rebootOnChange, condition)
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddPhoneNumberEditBox
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddPhoneNumberEditBox = function (name, value, length, size,
  onChange, isRequired, requiredText, rebootOnChange, condition)
{
  return this.AddEditBox (name, value, length, size, 'CheckPhoneInput',
    onChange, isRequired, requiredText, rebootOnChange, condition)
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddRow
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddRow = function ()
{
  this.CreateRow (arguments)
}

function onCondition (lValue, rValue)
{
  var bResults
  var object = GetObject (lValue)
  var value

  if (object)
  {
    value = GetObjectValue (lValue)
    //bResults = eval (value+rValue)
    try
    {
      bResults = eval (value+rValue)
    }
    catch (e)
    {
      bResults = eval ("'"+value+"'"+rValue)
    }
  }
  else
  {
    try
    {
      eval (lValue+rValue)
    }
    catch (e)
    {
      bResults = false
    }
  }

  return bResults
}

//////////////////////////////////////////////////////////////////////
//  Name:        CreateRow
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.CreateRow = function (rowArgs)
{
  var newRow = new Row ()
  //var rowArgs = arguments
  
  // Parse out the arguments
  newRow.SetRowNumber (this.currentRow)
  // Save the form that this is in so that we add to the
  // correct part of the DOM tree.
  newRow.dataTable = this.dataTableBody
  newRow.useColumns = this.useColumns
  for (var index = 0; index < rowArgs.length; index++)
  {
    // Ignore null fields. Don't ignore empty strings.
    if (rowArgs[index] == null) continue
    
    // Look for command arguments.
    if (typeof rowArgs[index] == "string" &&
        (args = rowArgs[index].match(/^([^ =]+)=(.+)$/)))
    {
      if (/(onchangeof)/i.test(args[1]))
      {
        newRow.dependentObjects.push (args[2])
      }
      else
      {
        var args2
        if (args2 = rowArgs[index].match(/^condition=([^ =]+)(==.+$)/))
        {
          newRow.SetAttribute ("condition",
            'onCondition("'+args2[1]+'", "'+args2[2]+'")')
          newRow.dependentObjects.push (args2[1].replace (/checkbox$/, ""))
        }
        else
        {
          newRow.SetAttribute (args[1], args[2])
        }
      }
    }
    else
    {
      var newObject = (typeof rowArgs[index] == "string") ?
        eval(rowArgs[index]) : rowArgs[index]
      // eval'ing the string may return null. If it does then 
      // do not add the object.
      if (newRow)
      {
        SetRowValue (newObject, this.currentRow)
        newRow.objects[newRow.objects.length] = newObject
      }
    }
    // The rest of the arguments are objects.
  }
  // Save the row data
  this.rows[this.currentRow++] = newRow
  // alert (newRow.rowNumber + ": " + this.rows[newRow.rowNumber])
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddTranslatedChoiceValue
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddTranslatedChoiceValue = function (choiceFileName,
  text, id, style, condition)
{
  return this.AddTextNode (TranslateOption (choiceFileName, text),
    id, style, condition)
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddTranslatedText
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddTranslatedText = function (text, id, style, condition)
{
  return this.AddTextNode (TranslateLangConst(text), id, style, condition)
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddLabel
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddLabel = function (text, id, style, condition)
{
  return this.AddTextNode (text, id + "_label", style, condition)
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddTextNode
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddTextNode = function (text, id, style, condition)
{
  var textNode
  
  if (!style) style = "textnode"
  if (!id) id = "textnode"+textNodeCount++
  if (!condition) condition = ""
  
  textNode = CreateElement ('<span id="'+id+'" name="'+id+'"'+
    ' class="'+style+'">')
  textNode.innerHTML = text
  this.SetCommonAttributes (textNode, false, condition)
  
  return textNode
}

function SubmitOnChangeToFrom (object, toValue, form, onSubmit)
{
  //if (form == null ) form = 0
  
  if (GetObjectValue (object) == toValue || GetObjectOValue (object) == toValue)
  {
    return SubmitOnChange (object, form, onSubmit)
  }
  return true
}

function SubmitOnChange (object, form, text, onSubmit)
{
  //if (form == null) form = 0
  if (text == null) text = MAKECHANGE_REFRESHES
  
  // Only do the submit if we are not setting the value back to the original value  
  if (GetObjectPValue (object) != GetObjectValue (object))
  {
    if (confirm (text))
    {
      page.Submit(form, onSubmit)
    }
    else
    {
      ResetObjectToPreviousValue (object)
      return false
    }
  }
  return true
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddRadioList
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddRadioList = function (name, values, selectedValue,
  onChange, isRequired, requiredText, rebootOnChange, multiLine,
  choiceFile, condition)
{
  var options
  var sOption
  var aOption
  var index
  var perRow = 0
  
  if (choiceFile == null) choiceFile = name
  if (onChange == null) onChange = "";
  
  onChange += ";UpdateDependentRows (this);"
  
  if (multiLine == null) multiLine = true;
  if (typeof multiLine == "number") 
  {
    perRow = multiLine
    multiLine = false
  }
  var newElement = document.createDocumentFragment()
  
//  if (rebootOnChange, condition) AddFootnoteIndecator ()

  if (values != null && values != "")
  {
    options = values.split ("?")
    for (index = 0; index < options.length; index++)
    {
      aOption = options[index].split("|")
      var text = TranslateOption (choiceFile, aOption[1])
      var value = aOption[0]
      var newOption = CreateElement 
        ('<input type="radio" id="'+name+'" name="'+name+'" onclick="'+onChange
         +'" value="' + value + '"' +((value == selectedValue) ? ' checked' : '')+'>')

      newOption.checked = (value == selectedValue)
      this.SetCommonAttributes (newOption, rebootOnChange, condition)
      newElement.appendChild (newOption)
      newElement.appendChild (
        (/(\.gif|\.png)$/.test (text)) ? 
          CreateElement ('<img src="'+text+'" border="0" hspace="1">') : 
          this.AddTextNode (text))
      if (multiLine || (perRow > 0 && (index + 1) % perRow == 0)) newElement.appendChild (CreateElement ('<br>'))
    }
  }

  return newElement;
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddSelectBox
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddSelectBox = function (name, values, size,
  onChange, rebootOnChange, 
  choiceFile, selectedValue, condition)
{
  return this.AddAnySelect (name, values,
    size, onChange, rebootOnChange, 
    choiceFile, selectedValue, condition)
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddSelect
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddSelect = function (name, values,
  onChange, rebootOnChange, 
  choiceFile, selectedValue, condition)
{
  return this.AddAnySelect (name, values,
    null, onChange, rebootOnChange, 
    choiceFile, selectedValue, condition)
}

//////////////////////////////////////////////////////////////////////
//  Name:        AddAnySelect
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddAnySelect = function (name, values,
  size, onChange, rebootOnChange, 
  choiceFile, selectedValue, condition)
{
  var options;
  var sOption;
  var aOption;
  var index;
  var newElement;
  var newOption;
  var text
  var defaultValue = ""
  var isFistLineADup = false
  var selectedIndex = 0
    
  if (!values) return null
  if (!size) size = ""
  var style = ""
  if (isNaN (size))
  {
    style = size
    size = ""
  }
    
  if (choiceFile == null) choiceFile = name
  if (onChange == null) onChange = "";
  onChange += ";page.UpdateCommonAttributes (this);UpdateDependentRows (this);"

   options = values.split ("?")
   // If there is only one choice create a text node instead of a drop down box.
   // The dynamically created serial port choice file some times have the same
   // value twice once to indecate that it is the default and once as the valid choice.
   if (options.length == 1 || (options.length == 2 && 
     options[0].split ("|")[0] == options[1].split ("|")[0]))
   {
     return this.AddTextNode (TranslateOption (choiceFile, options[0].split ("|")[0]), name)
   }
   
   // Create the select
   newElement = CreateElement ('<select align="absmiddle" class="'+style+'" id="'+
     name+'" name="'+name+'" onchange="'+onChange+'" size="'+size+'">')

   for (index = 0; index < options.length; index++)
   {
     aOption = options[index].split("|")
     newOption = newElement.appendChild (CreateElement('<option value="'+aOption[0]+'">'))
     // Since we now have access to all of the tranlated string constants.
     // We no longer need to rely on the server sending them to us.
     newOption.text = TranslateOption (choiceFile, aOption[0])
     // Once the server has been modified to not send the translated value
     // the line below can replace the line 2 rows down.
     // newOption.selected = aOption.length > 1
     if ((selectedValue && (selectedValue == aOption[0])) || 
       (!selectedValue && (aOption.length > 1 && aOption[aOption.length-1] == kSelected)))
         selectedIndex = index
     // alert (newOption.text + " is selected = " + newOption.selected )
     // If this is the first line save it as the default
     if (index == 0)
     {
       defaultValue = newOption.value
     }
     // If this is not the first line check to see if it is a dup of the first line
     // so that we can remove the fist line when we are done.
     else
     {
       if (!isFistLineADup) isFistLineADup = newOption.value == defaultValue
     }
   }

   if (isFistLineADup)
   {
     newElement.options[0] = null
     if (selectedIndex != 0) --selectedIndex
   }
 
   newElement.selectedIndex = selectedIndex
  
  this.SetCommonAttributes (newElement, rebootOnChange, condition)

  return newElement;
}
    
//////////////////////////////////////////////////////////////////////
//  Name:        GetButtonElement
//  Description: Get the Button Element
//////////////////////////////////////////////////////////////////////

Page.prototype.GetButtonElement = function ()
{
  return parent.document.getElementById ("buttons")
}
    
//////////////////////////////////////////////////////////////////////
//  Name:        AddHeaderButton
//  Description: Add buttons to the header
//////////////////////////////////////////////////////////////////////

Page.prototype.AddHeaderButton = function (button)
{
  var buttonElement = this.GetButtonElement ()
  if (!buttonElement)
  {
    parent.page.AddHeaderButton (button)
    return
  }
  buttonElement.insertAdjacentElement ("beforeend", button)
}
    
//////////////////////////////////////////////////////////////////////
//  Name:        AddUpdateNextButtons
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.AddUpdateNextButtons = function (backPage,
  nextPage, showUpdate, onSubmit, contentPage)
{
  var buttonElement = this.GetButtonElement ()
  if (!buttonElement)
  {
    parent.page.AddUpdateNextButtons (
      backPage, nextPage, showUpdate, onSubmit, this)
    return
  }
  if (contentPage == null) contentPage = this
  var form = this.formName ? "'" + contentPage.formName + "'" : "null"

  // Clear the old buttons
  RemoveChildren (buttonElement)

  //alert (onClick);
  if (showUpdate == null) showUpdate = (!isOOB && contentPage.formName)
  if (nextPage == null) nextPage = "";
  if (!onSubmit) onSubmit = "";

  if (showUpdate && !this.autoSubmit)
  {
    this.AddHeaderButton (this.CreateButton ("update", UPDATE,
      "page.CheckAndSubmitForm('"+onSubmit+"', "+form+")"))
  }
  if (backPage)
  {
    this.AddHeaderButton (this.CreateButton ("back", MENU_STR,
      "page.OnClickBack('"+backPage+"', '"+onSubmit+"', "+form+")"))
  }
  if (nextPage != "")
  {
    this.AddHeaderButton (this.CreateButton ("next", NEXT_STR,
      "page.OnClickNext('"+nextPage+"', '"+onSubmit+"', "+form+")"))
  }
}

Page.prototype.CreateButton = function (name, value, onclick, style)
{

  if (!style) style = "button"
  if (!onclick) onclick = ""
  
  return CreateElement ('<input type="button" id="'+name+
    '" name="'+name+'" onclick="'+onclick+'" value="'+value+
    '" class="'+style+'">')
}

//////////////////////////////////////////////////////////////////////
//  Name:        CreateHeaderTable
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.CreateHeaderTable = function ()
{
  var headerTable = 
    CreateElement ('<table id="headerTable" width="100%" border="0" cellspacing="0" cellpadding="2">')
  var tbody = headerTable.appendChild (CreateElement ('<tbody>'))
  var headerRow = tbody.appendChild (CreateElement('<tr class="pageTitle">'))
  
  headerRow.appendChild(CreateElement('<td class="pageTitle" id="pageTitle">'))
  headerRow.appendChild(CreateElement('<td name="buttons" id="buttons">'))
  
  return headerTable;
}

function SetAttributeValue (object, attribute, value)
{
  if (object)
  {
    if (object.setAttribute)
    {
      object.setAttribute (attribute, value)
    }
    if (object.hasChildNodes && object.hasChildNodes ())
    {
      //alert ("HasChildNodes")
      for (var child = 0; child < object.childNodes.length; child++)
      {
        SetAttributeValue (object.childNodes.item(child), attribute, value)
      }
    }
  }
}

function GetAttributeValue (object, attribute)
{
  var rValue = null
  
  if (object)
  {
    if (object.getAttribute)
    {
      rValue = object.getAttribute (attribute)
    }
    else if (object.hasChildNodes && object.hasChildNodes ())
    {
      //alert ("HasChildNodes")
      for (var child = 0; child < object.childNodes.length; child++)
      {
        rValue = GetAttributeValue (object.childNodes.item(child), attribute)
        if (rValue != null) break
      }
    }
  }
  return rValue
}

function SetRowValue (object, row)
{
  if (GetAttributeValue (object, "row") == -1)
  {
    SetAttributeValue (object, "row", row)
  }
}

function ShowObj (object)
{
  var bRValue = false
  if (object)
  {
    var objCondition = GetAttributeValue (object, "condition")
    objCondition = (objCondition) ? objCondition : ""
    bRValue = (objCondition == "" || eval (objCondition))
  }
  return bRValue
}

//////////////////////////////////////////////////////////////////////
//  Name:        UpdateLabel
//  Description: Update the label element of a row
//////////////////////////////////////////////////////////////////////

Page.prototype.UpdateLabel = function (row, newValue)
{
  var labelId = row + "label"
  var label = document.getElementById(labelId)
  if (label) label.innerHTML = newValue
}

//////////////////////////////////////////////////////////////////////
//  Name:        CreateFootnoteIndecator
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.CreateFootnoteIndecator = function ()
{
  return document.createTextNode(" *")
}

//////////////////////////////////////////////////////////////////////
//  Name:        RegisterForChanges
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.RegisterForChanges = function (dependentObjects, rowNumber)
{
  var row
  var index
  var objects
  var object
  var isDup
  var dependentRows
  
  // alert ("Register row " + rowNumber + " for changes to "+dependentObjects)
  
  for (index in dependentObjects)
  {
    // object = document.getElementById (dependentObjects[index])
    object = this.FindObjectById (dependentObjects[index])
    isDup = false
    // Don't add a row more than once.
    if (object)
    {
      dependentRows = GetArrayAttribute (object, kDependentRows)
      for (row in dependentRows)
      {
        if (dependentRows[row] == rowNumber)
        {
          isDup = true
          break
        }
      }
      if (!isDup)
      {
        dependentRows.push (rowNumber)
        dependentRows.sort (numberorder)
        SetArrayAttribute (object, kDependentRows, dependentRows)
        this.RegisterForChanges (this.rows[object.getAttribute ("row")].dependentObjects, rowNumber)
      }
    }
  }
}

function FindObjectById (object, id)
{
  var results
  //alert ("FindObjectById ("+object+", "+id+")")
  if (object)
  {
    if (object.id)
    {
      // alert ("FindObjectById : object.id = "+object.id+" looking for "+id)
      if (object.id == id) return object
    }
    if (object.hasChildNodes ())
    {
      //alert ("HasChildNodes")
       for (var child = 0; child < object.childNodes.length; child++)
      {
        results = FindObjectById (object.childNodes.item(child), id)
        if (results != null) return results
      }
    }
  }
  return null
}

Page.prototype.FindObjectById = function (id)
{
  var rowIndex
  var objectIndex
  var resultsObj
  
  for (rowIndex in this.rows)
  {
    for (objectIndex in this.rows[rowIndex].objects)
    {
      resultsObj = FindObjectById (this.rows[rowIndex].objects[objectIndex], id)
      if (resultsObj) {/*alert ("FindObjectById ("+id+") : FOUND");*/return resultsObj}
    }
  }
  return null
}

function SetArrayAttribute (object, attribute, arrayValues)
{
  var aValue = ""
  for (var arrayValue in arrayValues)
  {
    if (aValue != "") aValue += kAttributeSeperator
    aValue += arrayValue + kAttValueSeperator + arrayValues [arrayValue]
  }
  // alert ("Saving " + attribute + " as \"" + aValue + "\"")
  object.setAttribute (attribute, aValue)
}

function GetArrayAttribute (object, attribute)
{
  var values = object.getAttribute (attribute)
  var results = new Array ()
  var valueAttPairs = values.split (kAttributeSeperator)
  
  // alert ("values = \"" + values + "\"")
  if (values != "")
  {
    for (var valueAttPair in valueAttPairs)
    {
      valueAndAttributes = valueAttPairs[valueAttPair].split (kAttValueSeperator)
      results [valueAndAttributes[0]] = valueAndAttributes[1]
    }
  }
  // alert ("Getting " + attribute + " as \"" + results + "\"")
  return results
}

function GetBooleanAttribute (object, attribute)
{
  var value = (object)?object.getAttribute (attribute):"false";
  
  // getAttribute in NS and Firefox only returns string so we need to convert
  // to boolean
  if (typeof value == "string") return value == "true"
  else return value
}

//////////////////////////////////////////////////////////////////////
//  Name:        
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.UpdateCommonAttributes = function (object)
{
  var currentValue = GetObjectValue (object)
  var oldCurrentValue = GetObjectCValue (object)
  var pageObj = this.FindObjectById (object.id)
  
  // Update previous value to the old current value
  object.setAttribute ("pValue", oldCurrentValue)
  // Update the current value with the objects actual value
  object.setAttribute ("cValue", currentValue)

  if (pageObj)
  {
    // Now do the same for row data so if we remove and add this element
    // we do not loss this data
    pageObj.setAttribute ("pValue", oldCurrentValue)
    pageObj.setAttribute ("cValue", currentValue)
    SetObjectValue (pageObj, currentValue, false)
  }
  return true
}

//////////////////////////////////////////////////////////////////////
//  Name:        SetCommonAttributes
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.SetCommonAttributes = function (objectID, rebootOnChange, condition)
{
  var object = objectID;
  rebootOnChange = (rebootOnChange == true)// Check for true in case it is null
  
  if (object)
  {
    var value = GetObjectValue (object)
    object.setAttribute ("oValue", value)
    object.setAttribute ("cValue", value)
    object.setAttribute ("pValue", value)
    object.setAttribute ("rebootOnChange", rebootOnChange)
    object.setAttribute ("row", -1)
    if (rebootOnChange) this.bootOnSomeChanges = true
    SetArrayAttribute (object, kDependentRows, new Array ())
    object.setAttribute ("condition", (condition) ? condition : "")
    Disable (object, IsProvisioned (object.id))
  }
  return object
}

Page.prototype.GetGroup = function (form)
{
  var groupObj = document.forms[(!form) ? this.formName : form]._groupname
  return document.forms[(!form) ? this.formName : form]._groupname.value
}
Page.prototype.SetGroup = function (group, form)
{
  document.forms[(!form) ? this.formName : form]._groupname.value = group
}

Page.prototype.SetAction = function (action, form)
{
  document.forms[(!form) ? this.formName : form].action = action
}

Page.prototype.GetAction = function (form)
{
  return document.forms[(!form) ? this.formName : form].action
}

Page.prototype.Submit = function (form, onSubmit)
{
  if (onSubmit) eval (onSubmit)
  document.forms[((!form) ? this.formName : form)].submit ()
}

//////////////////////////////////////////////////////////////////////
//  Name:        ShowHideRow
//  Description: Description
//////////////////////////////////////////////////////////////////////

Page.prototype.ShowHideRow = function (rowIndex)
{
  var rowData = this.rows[rowIndex]
  var oldRow
  var previousRow = null;
  var newRow
  var rowID = rowData.GetRowID ()
  var index
  
  if (rowData.Show ())
  {
    // If the element does not exits add it
    oldRow = document.getElementById (rowID)
    newRow = rowData.CreateRow ()
    if (oldRow == null)
    {
      // Find the fist row that exists before the postion we want to add this row.
      for (index = rowData.rowNumber - 1; previousRow == null && index >= 0; index--)
      {
        previousRow = document.getElementById (this.rows[index].GetRowID());
      }
      // If previous row is still null we are going to add this elemnt to the top
      if (previousRow == null) previousRow = rowData.dataTable
      previousRow.insertAdjacentElement ("afterEnd", newRow)
    }
    // If it does exist update it to the new one
    else
    {
      oldRow.replaceNode (newRow)
    }
    if (rowData.oncreationof) eval (rowData.oncreationof)
    if (rowData.onshow) eval (rowData.onshow)
  }
  // otherwise hide it
  else
  {
    // If the element exists remove it
    if (document.getElementById (rowID) != null)
    {
      RemoveElements (rowID);
      if (rowData.onhide) eval (rowData.onhide)
    }
  }
}

//////////////////////////////////////////////////////////////////////
//  Name:        Row
//  Description: Description
//////////////////////////////////////////////////////////////////////

function Row ()
{
  this.tabed = page.currentIndent
  this.style = ""
  this.labelstyle = ""
  this.datastyle = ""
  this.dataColumns = 1
  this.columns = 1
  this.width = "40%"
  this.condition = null
  this.objects = new Array ()
  this.rowNumber = null
  this.dependentObjects = new Array ()
  this.oncreation = null
  this.dataTable = null
  this.useColumns = false
  this.name = ""
}

//////////////////////////////////////////////////////////////////////
//  Name:        CreateRow
//  Description: Create a new row object
//////////////////////////////////////////////////////////////////////

Row.prototype.CreateRow = function ()
{
  var index
  var newElement
  var rowElement = null
  var newNode
  var rowId = this.GetRowID ()
  var dataId = this.GetDataID ()
  var labelId = this.GetLabelID ()
  var labelStyle = (this.labelstyle) ? this.labelstyle : 
    (this.style) ? this.style : "defaultRow"
  var dataStyle = (this.datastyle) ? this.datastyle :
    (this.style) ? this.style : "defaultData"
  var objCondition
   
  if (this.Show ())
  {
    var noWrap = (this.columns == 1) ? "nowrap " : ""
  
    rowElement = CreateElement ('<tr id="'+rowId+'" class="'+this.style+'">')
    
    // Create the label
    newTD = CreateElement ('<td '+noWrap+'colspan="'+this.columns+'" id="'+
        labelId+'" class="'+labelStyle+'">')
    newTD.nowrap = (this.columns == 1)
    newElement = rowElement.appendChild (newTD)
    newElement.style.paddingLeft = (14 * this.tabed) + "px"
    
    for (index = 0; index < this.objects.length; index++)
    {
      var labelObj = this.objects[index]
      // If the object is empty or null leave the label empty
      if  (labelObj == "" || labelObj == null) break
      // Otherwise show the first object that does not have its
      // condition set to false.
      if (ShowObj (labelObj))
      {
        newElement.appendChild (labelObj.cloneNode (true))
        break
      }
    }

    ++index

    // If we are not using columns create the td outside of the loop
    if (!this.useColumns && index < this.objects.length)
      newElement = rowElement.appendChild (CreateElement
        ('<td colspan="'+this.dataColumns+'" id="'+dataId+
         '" class="'+dataStyle+'">'))

    for (; index < this.objects.length; index++)
    {
      // If we are using columns then we need to create a new
      // td for each element.
      if (this.useColumns)
      {
        newElement = rowElement.appendChild (
          CreateElement ('<td id="'+dataId+(index-1)+'" class="'+dataStyle+'">'))
      }
      else
      {
        if (index != 1) newElement.appendChild (document.createTextNode(" "))
      }
      
      if (ShowObj (this.objects[index]))
      {
        // Create the object
        newNode = this.objects[index].cloneNode (true)

        // The selected object was not being copied. Maybe we need to us a documentFragment
        if (this.objects[index].selectedIndex)
          newNode.selectedIndex = this.objects[index].selectedIndex
        
        // Add the object
        newElement.appendChild (newNode)
      
        // Add a star at the end of the element if changing it will cause a reboot.
        if (RebootOnChange (this.objects[index]))
        {
          var footnoteIndecator = page.CreateFootnoteIndecator ()
          newElement.appendChild (footnoteIndecator)
        }
      }
    }
  }
  return rowElement;
}

//////////////////////////////////////////////////////////////////////
//  Name:        GetRowID
//  Description: Description
//////////////////////////////////////////////////////////////////////

Row.prototype.GetRowID = function ()
{
  return (this.name == "") ? "row" + this.rowNumber : this.name
}

//////////////////////////////////////////////////////////////////////
//  Name:        GetLabelID
//  Description: Description
//////////////////////////////////////////////////////////////////////

Row.prototype.GetLabelID = function ()
{
  return this.GetRowID () + "label"
}

//////////////////////////////////////////////////////////////////////
//  Name:        GetDataID
//  Description: Description
//////////////////////////////////////////////////////////////////////

Row.prototype.GetDataID = function ()
{
  return this.GetRowID () + "data"
}

//////////////////////////////////////////////////////////////////////
//  Name:        SetAttribute
//  Description: Used to set an arbitrary row attribute
//////////////////////////////////////////////////////////////////////

Row.prototype.SetAttribute = function (attribute, value)
{
  this[attribute] = value
}

//////////////////////////////////////////////////////////////////////
//  Name:        SetRowNumber
//  Description: Description
//////////////////////////////////////////////////////////////////////

Row.prototype.SetRowNumber = function (rowNumber)
{
  this.rowNumber = rowNumber
}

//////////////////////////////////////////////////////////////////////
//  Name:        Show ()
//  Description: Return true if the rows condition attribute evaluates
//               to true
//////////////////////////////////////////////////////////////////////

Row.prototype.Show = function ()
{
  return !this.condition || eval (this.condition)
}

//////////////////////////////////////////////////////////////////////
//  Name:        UpdateDependentRows
//  Description: Description
//////////////////////////////////////////////////////////////////////

function UpdateDependentRows (object)
{
  var dependentRows = GetArrayAttribute (object, kDependentRows)
  //alert ("UpdateDependentRows ("+object.id+") : " + dependentRows)
  
  for (var index = 0; index < dependentRows.length; index++)
  {
    page.ShowHideRow (dependentRows [index])
  }
}
