function ProductFormSelector() {
  var self = this;
  this.o = null;
  this.products = [];

  this.add = function(oSeries,oType,oGuideLink) {
    // generic product object
    var x = new Object();
    x.series = oSeries;
    x.type = oType;
    x.GuideLink = oGuideLink;
    self.products[self.products.length] = x;
  }

  this.select = function(selType,selElement) {
    writeDebug('ProductFormSelector.select('+selType+','+selElement);
    var items = [];

    var attrType = null; // attribute name to use for drop-down item label (what user sees)
    var attrTypeValue = null; // attribute name to use for drop-down value (submitted in form)
    var oTarget = null;
    
    if (selType=='series') {
      // show list of unique matching types in "type" dropdown
      oTarget = self.o[1];
      attrType = 'type';
      attrTypeValue = 'GuideLink';
      tmpItems = self.getItemsByAttribute('series',selElement[selElement.selectedIndex].value);
      tmpTypes = [];
      items = [];
      // build array of unique types matching given series
      for (var i=0; i<tmpItems.length; i++) {
        if (!tmpTypes[tmpItems[i].type]) {
          tmpTypes[tmpItems[i].type] = true;
          items[items.length] = tmpItems[i];
        }
      }
    }
    
    writeDebug('ProductFormSelector.select(): Found '+items.length+' matches.');
    
    // populate target with results
    var oSel = null;
    oTarget.innerHTML = '';
    for (var i=0; i<items.length; i++) {
      oSel = document.createElement('option');
      oSel.name = attrTypeValue;
      oSel.id = attrTypeValue;
      oSel.value = items[i][attrTypeValue];
      oSel.innerHTML = items[i][attrType];
      oTarget.appendChild(oSel);
    }
    
    // this.select()

  }

  this.getItemsByAttribute = function(attrName,attrValue) {
    // get items by name/value or name/value array pairs
    writeDebug('getItemsByAttribute('+attrName+','+attrValue+')');
    var attrNames = typeof(attrName)!='object'?[attrName]:attrName;
    var attrValues = typeof(attrValue)!='object'?[attrValue]:attrValue;
    var matches = [];
    var match = null;
    var j=0;
    for (var i=0; i<self.products.length; i++) {
      for (j=0; j<attrNames.length; j++) {
        match = true;
        if (self.products[i][attrNames[j]] != attrValues[j]) {
          match = false;
          break;
        }
      }
      if (match) {
       matches[matches.length] = self.products[i];
      }
    }
    return matches;
  }

  this.init = function() {
    self.oParent = document.getElementById('product-selector'); // form element
    self.o = self.oParent.elements; // getElementsByTagName('select') breaks in NN6.2
    if (!self.o) {
      writeDebug('ProductFormSelector.init(): Could not find form element(s).');
    }
    // make a default selection
    self.select('series',self.o[0]);
  }

}

var pfs = new ProductFormSelector();
