// ===================================================================
// Author: Matt Kruse <matt@mattkruse.com>
// WWW: http://www.mattkruse.com/
//
// NOTICE: You may use this code for any purpose, commercial or
// private, without any further permission from the author. You may
// remove this notice from your final code if you wish, however it is
// appreciated by the author if at least my web site address is kept.
//
// You may *NOT* re-distribute this code in any way except through its
// use. That means, you can include it in your product, or your web
// site, or any other form where the code is actually being used. You
// may not put the plain javascript up on your site for download or
// include it in your javascript libraries for download. 
// If you wish to share this code with others, please just point them
// to the URL instead.
// Please DO NOT link directly to my .js files from your site. Copy
// the files to your server and use them there. Thank you.
// ===================================================================
var dynamicOptionListCount = 0; 
var dynamicOptionListObjects = new Array(); 
function initDynamicOptionLists() {
   for(var i = 0; i < dynamicOptionListObjects.length; i++) {
      var dol = dynamicOptionListObjects[i]; 
      if(dol.formName != null) {
         dol.form = document.forms[dol.formName]; 
         }
      else if(dol.formIndex != null) {
         dol.form = document.forms[dol.formIndex]; 
         }
      else {
         var name = dol.fieldNames[0][0]; 
         for(var f = 0; f < document.forms.length; f++) {
            if(typeof(document.forms[f][name]) != "undefined") {
               dol.form = document.forms[f]; 
               break; 
               }
            }
         if(dol.form == null) {
            alert("ERROR: Couldn't find form element " + name + " in any form on the page! Init aborted"); 
            return; 
            }
         }
      for(var j = 0; j < dol.fieldNames.length; j++) {
         for(var k = 0; k < dol.fieldNames[j].length - 1; k++) {
            var selObj = dol.form[dol.fieldNames[j][k]]; 
            if(typeof(selObj) == "undefined") {
               alert("Select box named " + dol.fieldNames[j][k] + " could not be found in the form. Init aborted"); 
               return; 
               }
            if(k == 0) {
               if(selObj.options != null) {
                  for(l = 0; l < selObj.options.length; l++) {
                     var sopt = selObj.options[l]; 
                     var m = dol.findMatchingOptionInArray(dol.options, sopt.text, sopt.value, false); 
                     if(m != null) {
                        var reselectForNN6 = sopt.selected; 
                        var m2 = new Option(sopt.text, sopt.value, sopt.defaultSelected, sopt.selected); 
                        m2.selected = sopt.selected; 
                        m2.defaultSelected = sopt.defaultSelected; 
                        m2.DOLOption = m; 
                        selObj.options[l] = m2; 
                        selObj.options[l].selected = reselectForNN6; 
                        }
                     }
                  }
               }
            if(selObj.onchange == null) {
               selObj.onchange = new Function("dynamicOptionListObjects[" + dol.index + "].change(this)"); 
               }
            }
         }
      }
   resetDynamicOptionLists(); 
   }
   
function resetDynamicOptionLists(theform) {
   for(var i = 0; i < dynamicOptionListObjects.length; i++) {
      var dol = dynamicOptionListObjects[i]; 
      if(typeof(theform) == "undefined" || theform == null || theform == dol.form) {
         for(var j = 0; j < dol.fieldNames.length; j++) {
            dol.change(dol.form[dol.fieldNames[j][0]], true); 
            }
         }
      }
   }
   
function DOLOption(text, value, defaultSelected, selected) {
   this.text = text; 
   this.value = value; 
   this.defaultSelected = defaultSelected; 
   this.selected = selected; 
   this.options = new Array(); 
   return this; 
   }
function DynamicOptionList() {
   this.form = null; 
   this.options = new Array(); 
   this.longestString = new Array(); 
   this.numberOfOptions = new Array(); 
   this.currentNode = null; 
   this.currentField = null; 
   this.currentNodeDepth = 0; 
   this.fieldNames = new Array(); 
   this.formIndex = null; 
   this.formName = null; 
   this.fieldListIndexes = new Object(); 
   this.fieldIndexes = new Object(); 
   this.selectFirstOption = true; 
   this.numberOfOptions = new Array(); 
   this.longestString = new Array(); 
   this.values = new Object(); 
   this.forValue = DOL_forValue; 
   this.forText = DOL_forText; 
   this.forField = DOL_forField; 
   this.forX = DOL_forX; 
   this.addOptions = DOL_addOptions; 
   this.addOptionsTextValue = DOL_addOptionsTextValue; 
   this.setDefaultOptions = DOL_setDefaultOptions; 
   this.setValues = DOL_setValues; 
   this.setValue = DOL_setValues; 
   this.setFormIndex = DOL_setFormIndex; 
   this.setFormName = DOL_setFormName; 
   this.printOptions = DOL_printOptions; 
   this.addDependentFields = DOL_addDependentFields; 
   this.change = DOL_change; 
   this.child = DOL_child; 
   this.selectChildOptions = DOL_selectChildOptions; 
   this.populateChild = DOL_populateChild; 
   this.change = DOL_change; 
   this.addNewOptionToList = DOL_addNewOptionToList; 
   this.findMatchingOptionInArray = DOL_findMatchingOptionInArray; 
   if(arguments.length > 0) {
      for(var i = 0; i < arguments.length; i++) {
         this.fieldListIndexes[arguments[i].toString()] = this.fieldNames.length; 
         this.fieldIndexes[arguments[i].toString()] = i; 
         }
      this.fieldNames[this.fieldNames.length] = arguments; 
      }
   this.index = window.dynamicOptionListCount++; 
   window["dynamicOptionListObjects"][this.index] = this; 
   }
function DOL_findMatchingOptionInArray(a, text, value, exactMatchRequired) {
   if(a == null || typeof(a) == "undefined") {
      return null; 
      }
   var value_match = null; 
   var text_match = null; 
   for(var i = 0; i < a.length; i++) {
      var opt = a[i]; 
      if(opt.value == value && opt.text == text) {
         return opt; 
         }
      if(!exactMatchRequired) {
         if(value_match == null && value != null && opt.value == value) {
            value_match = opt; 
            }
         if(text_match == null && text != null && opt.text == text) {
            text_match = opt; 
            }
         }
      }
   return(value_match != null) ? value_match : text_match; 
   }
function DOL_forX(s, type) {
   if(this.currentNode == null) {
      this.currentNodeDepth = 0; 
      }
   var useNode = (this.currentNode == null) ? this : this.currentNode; 
   var o = this.findMatchingOptionInArray(useNode["options"], (type == "text") ? s : null, (type == "value") ? s : null, false); 
   if(o == null) {
      o = new DOLOption(null, null, false, false); 
      o[type] = s; 
      useNode.options[useNode.options.length] = o; 
      }
   this.currentNode = o; 
   this.currentNodeDepth++; 
   return this; 
   }
function DOL_forValue(s) {
   return this.forX(s, "value"); 
   }
function DOL_forText(s) {
   return this.forX(s, "text"); 
   }
function DOL_forField(f) {
   this.currentField = f; 
   return this; 
   }
function DOL_addNewOptionToList(a, text, value, defaultSelected) {
   var o = new DOLOption(text, value, defaultSelected, false); 
   if(a == null) {
      a = new Array(); 
      }
   for(var i = 0; i < a.length; i++) {
      if(a[i].text == o.text && a[i].value == o.value) {
         if(o.selected) {
            a[i].selected = true; 
            }
         if(o.defaultSelected) {
            a[i].defaultSelected = true; 
            }
         return a; 
         }
      }
   a[a.length] = o; 
   }
function DOL_addOptions() {
   if(this.currentNode == null) {
      this.currentNode = this; 
      }
   if(this.currentNode["options"] == null) {
      this.currentNode["options"] = new Array(); 
      }
   for(var i = 0; i < arguments.length; i++) {
      var text = arguments[i]; 
      this.addNewOptionToList(this.currentNode.options, text, text, false); 
      if(typeof(this.numberOfOptions[this.currentNodeDepth]) == "undefined") {
         this.numberOfOptions[this.currentNodeDepth] = 0; 
         }
      if(this.currentNode.options.length > this.numberOfOptions[this.currentNodeDepth]) {
         this.numberOfOptions[this.currentNodeDepth] = this.currentNode.options.length; 
         }
      if(typeof(this.longestString[this.currentNodeDepth]) == "undefined" || (text.length > this.longestString[this.currentNodeDepth].length)) {
         this.longestString[this.currentNodeDepth] = text; 
         }
      }
   this.currentNode = null; 
   this.currentNodeDepth = 0; 
   }
function DOL_addOptionsTextValue() {
   if(this.currentNode == null) {
      this.currentNode = this; 
      }
   if(this.currentNode["options"] == null) {
      this.currentNode["options"] = new Array(); 
      }
   for(var i = 0; i < arguments.length; i++) {
      var text = arguments[i++]; 
      var value = arguments[i]; 
      this.addNewOptionToList(this.currentNode.options, text, value, false); 
      if(typeof(this.numberOfOptions[this.currentNodeDepth]) == "undefined") {
         this.numberOfOptions[this.currentNodeDepth] = 0; 
         }
      if(this.currentNode.options.length > this.numberOfOptions[this.currentNodeDepth]) {
         this.numberOfOptions[this.currentNodeDepth] = this.currentNode.options.length; 
         }
      if(typeof(this.longestString[this.currentNodeDepth]) == "undefined" || (text.length > this.longestString[this.currentNodeDepth].length)) {
         this.longestString[this.currentNodeDepth] = text; 
         }
      }
   this.currentNode = null; 
   this.currentNodeDepth = 0; 
   }
function DOL_child(obj) {
   var listIndex = this.fieldListIndexes[obj.name]; 
   var index = this.fieldIndexes[obj.name]; 
   if(index < (this.fieldNames[listIndex].length - 1)) {
      return this.form[this.fieldNames[listIndex][index + 1]]; 
      }
   return null; 
   }
function DOL_setDefaultOptions() {
   if(this.currentNode == null) {
      this.currentNode = this; 
      }
   for(var i = 0; i < arguments.length; i++) {
      var o = this.findMatchingOptionInArray(this.currentNode.options, null, arguments[i], false); 
      if(o != null) {
         o.defaultSelected = true; 
         }
      }
   this.currentNode = null; 
   }
function DOL_setValues() {
   if(this.currentField == null) {
      alert("Can't call setValues() without using forField() first!"); 
      return; 
      }
   if(typeof(this.values[this.currentField]) == "undefined") {
      this.values[this.currentField] = new Object(); 
      }
   for(var i = 0; i < arguments.length; i++) {
      this.values[this.currentField][arguments[i]] = true; 
      }
   this.currentField = null; 
   }
function DOL_setFormIndex(i) {
   this.formIndex = i; 
   }
function DOL_setFormName(n) {
   this.formName = n; 
   }
function DOL_printOptions(name) {
   if((navigator.appName == 'Netscape') && (parseInt(navigator.appVersion) <= 4)) {
      var index = this.fieldIndexes[name]; 
      var ret = ""; 
      if(typeof(this.numberOfOptions[index]) != "undefined") {
         for(var i = 0; i < this.numberOfOptions[index]; i++) {
            ret += "<OPTION>"; 
            }
         }
      ret += "<OPTION>"; 
      if(typeof(this.longestString[index]) != "undefined") {
         for(var i = 0; i < this.longestString[index].length; i++) {
            ret += "_"; 
            }
         }
      document.writeln(ret); 
      }
   }
function DOL_addDependentFields() {
   for(var i = 0; i < arguments.length; i++) {
      this.fieldListIndexes[arguments[i].toString()] = this.fieldNames.length; 
      this.fieldIndexes[arguments[i].toString()] = i; 
      }
   this.fieldNames[this.fieldNames.length] = arguments; 
   }
function DOL_change(obj, usePreselected) {
   if(usePreselected == null || typeof(usePreselected) == "undefined") {
      usePreselected = false; 
      }
   var changedListIndex = this.fieldListIndexes[obj.name]; 
   var changedIndex = this.fieldIndexes[obj.name]; 
   var child = this.child(obj); 
   if(child == null) {
      return; 
      }
   if(obj.type == "select-one") {
      if(child.options != null) {
         child.options.length = 0; 
         }
      if(obj.options != null && obj.options.length > 0 && obj.selectedIndex >= 0) {
         var o = obj.options[obj.selectedIndex]; 
         this.populateChild(o.DOLOption, child, usePreselected); 
         this.selectChildOptions(child, usePreselected); 
         }
      }
   else if(obj.type == "select-multiple") {
      var currentlySelectedOptions = new Array(); 
      if(!usePreselected) {
         for(var i = 0; i < child.options.length; i++) {
            var co = child.options[i]; 
            if(co.selected) {
               this.addNewOptionToList(currentlySelectedOptions, co.text, co.value, co.defaultSelected); 
               }
            }
         }
      child.options.length = 0; 
      if(obj.options != null) {
         var obj_o = obj.options; 
         for(var i = 0; i < obj_o.length; i++) {
            if(obj_o[i].selected) {
               this.populateChild(obj_o[i].DOLOption, child, usePreselected); 
               }
            }
         var atLeastOneSelected = false; 
         if(!usePreselected) {
            for(var i = 0; i < child.options.length; i++) {
               var m = this.findMatchingOptionInArray(currentlySelectedOptions, child.options[i].text, child.options[i].value, true); 
               if(m != null) {
                  child.options[i].selected = true; 
                  atLeastOneSelected = true; 
                  }
               }
            }
         if(!atLeastOneSelected) {
            this.selectChildOptions(child, usePreselected); 
            }
         }
      }
   this.change(child, usePreselected); 
   }
function DOL_populateChild(dolOption, childSelectObj, usePreselected) {
   if(dolOption != null && dolOption.options != null) {
      for(var j = 0; j < dolOption.options.length; j++) {
         var srcOpt = dolOption.options[j]; 
         if(childSelectObj.options == null) {
            childSelectObj.options = new Array(); 
            }
         var duplicate = false; 
         var preSelectedExists = false; 
         for(var k = 0; k < childSelectObj.options.length; k++) {
            var csi = childSelectObj.options[k]; 
            if(csi.text == srcOpt.text && csi.value == srcOpt.value) {
               duplicate = true; 
               break; 
               }
            }
         if(!duplicate) {
            var newopt = new Option(srcOpt.text, srcOpt.value, false, false); 
            newopt.selected = false; 
            newopt.defaultSelected = false; 
            newopt.DOLOption = srcOpt; 
            childSelectObj.options[childSelectObj.options.length] = newopt; 
            }
         }
      }
   }
function DOL_selectChildOptions(obj, usePreselected) {
   var values = this.values[obj.name]; 
   var preselectedExists = false; 
   if(usePreselected && values != null && typeof(values) != "undefined") {
      for(var i = 0; i < obj.options.length; i++) {
         var v = obj.options[i].value; 
         if(v != null && values[v] != null && typeof(values[v]) != "undefined") {
            preselectedExists = true; 
            break; 
            }
         }
      }
   var atLeastOneSelected = false; 
   for(var i = 0; i < obj.options.length; i++) {
      var o = obj.options[i]; 
      if(preselectedExists && o.value != null && values[o.value] != null && typeof(values[o.value]) != "undefined") {
         o.selected = true; 
         atLeastOneSelected = true; 
         }
      else if(!preselectedExists && o.DOLOption != null && o.DOLOption.defaultSelected) {
         o.selected = true; 
         atLeastOneSelected = true; 
         }
      else {
         o.selected = false; 
         }
      }
   if(this.selectFirstOption && !atLeastOneSelected && obj.options.length > 0) {
      obj.options[0].selected = true; 
      }
   else if(!atLeastOneSelected && obj.type == "select-one") {
      obj.selectedIndex = - 1; 
      }
   }