function ButtonWidget(debug,defer,allowFocus) {
  // debug (true/false): enables debugging mode
  // defer (true/false): defers init() call (will have to be called manually)
  // noNetscapeBlur (true/false): allows buttons to get and keep focus (annoying inner border shown - workaround for Netscape 7.0 when buttons in <fieldset> tags, ie. demo page)
  var self = this;
  this.debugEnabled = (debug?1:0);
  this.defer = (defer?1:0);
  this.noFocus = (allowFocus?0:1);
  this.netscape60 = ((navigator.userAgent.toString().indexOf('Netscape6/6.0')+1)?1:0);
  if (!ua) {
    window.status = 'ButtonWidget(): object "ua" null or undefined/undeclared (utils.js)';
	return false;
  }
  this.b = document.getElementsByTagName("button");
  this.classNameActive = 'down'; // Extension appended to button class name when active ("down").
  this.classNameSeparator = '-'; // Character that divides CSS class "sections", ie. color-one
  this.classKeyName = 'type'+this.classNameSeparator; // Class name to search for and append active ("down") state to, ie. "type-"
  this.fixClasses = ['ie5mac','opera','safari']; // Class names for correcting CSS bugs etc. particular to browsers
  this.fixClassConditions = [(ua.ie && ua.mac),(ua.opera),(ua.safari)]; // Stored results for browser tests
  this.returnActiveClass = function(classNames) {
    this.foundMatch = 0;
    this.classNames = classNames.split(' ');
    for (var i=0;i<this.classNames.length;i++) {
      if (this.classNames[i].indexOf(this.classKeyName)>=0 || this.classNames[i].indexOf('feature')>=0) { // Add active ("down") class extension to class name - eg. "type-one" becomes "type-one-down"
	    this.classNames[i] += this.classNameSeparator + this.classNameActive;
		this.foundMatch = 1;
		break;
	  }
    }
    return (!this.foundMatch?this.classNameActive+' ':'')+this.classNames.join(' '); // If no type class provided (!this.foundMatch), set "down" as first class name so ie5:mac CSS whitespace parse bug is avoided (otherwise other "-down" classes will be inherited.)
  }
  this.appendFixClass = function(o,className) {
	o.bwClassNames = className+' '+o.bwClassNames; // prepend "fix" class
  }
  
  this.init = function() {
    // Main loop (assigns button event handlers etc.)
    for (var i=0; i<this.b.length; i++) {
	  this.b[i].bwClassNames = this.b[i].className?this.b[i].className:''; // Stores original appended class names (if any)
	  for (var j=0; j<this.fixClasses.length; j++) {
	    if (this.fixClassConditions[j]) { 
	      this.appendFixClass(this.b[i],this.fixClasses[j]); // Prepend corrective classes if needed
	    }
      }	
	  this.b[i].bwClassNamesActive = this.b[i].bwClassNames?this.returnActiveClass(this.b[i].bwClassNames):this.classNameActive; // "Active" class to be appended (assigned + active if classes declared (see returnActiveClass()), default active class name if otherwise.)
      this.b[i].className = this.b[i].bwClassNames; // apply fixes, if any
	  this.b[i].htmlMouseDownHandler = (this.b[i].onmousedown?this.b[i].onmousedown:function(){});
	  this.b[i].htmlMouseUpHandler = (this.b[i].onmouseup?this.b[i].onmouseup:function(){});
	  this.b[i].htmlMouseOutHandler = (this.b[i].onmouseout?this.b[i].onmouseout:function(){});
	  this.b[i].onmousedown = function() {
	    this.className = this.bwClassNamesActive;
	    if (self.debugEnabled) {
	      this.debug();
	    }
	    this.htmlMouseDownHandler();
	  }
      this.b[i].onmouseup = function() {
  	    this.className = this.bwClassNames;
		if (!self.netscape60) {
 		  this.blur();
		}
	    if (self.debugEnabled) {
	      this.debug();
	    }
	    this.htmlMouseUpHandler();
	  }
	  if (this.noFocus) {
	    this.b[i].onfocus = function() {
	      this.blur();
	    }
	  }
	  this.b[i].onmouseout = function() {
	    this.className = this.bwClassNames;
		if (ua.ie) {
		  this.blur();
		}
		if (self.debugEnabled) {
		  this.debug();
		}
		this.htmlMouseOutHandler();
	  }
	  if (self.debugEnabled) {
	    this.b[i].onmouseover = function() {
		  this.debug();
		}
	  }
      this.b[i].debug = function() {
	    window.status = 'ButtonWidget(): '+this.className;
	  }
    }
  }
  if (!this.defer) {
    this.init();
  }
}

function buttonWidgetCSSFix() {
  var cssObj = document.styleSheets;
  var cssRules = null;
  for (var i=0; i<cssObj.length; i++) {
    if (cssObj[i].title == 'buttons') {
      cssRules = cssObj[i].cssRules?cssObj[i].cssRules:cssObj[i].rules;
	}
  }
  if (cssRules) {
    for (var j=0; j<cssRules.length; j++) {
	  if (cssRules[j].style.width) {
	    cssRules[j].style.width = (parseInt(cssRules[j].style.width)-3)+'px';
	  }
	}
  }
}

if (ua.mac && (ua.ie || ua.safari)) {
  buttonWidgetCSSFix();
}

var buttonWidget = null;

onloadHandlers[onloadHandlers.length] = 'buttonWidget = new ButtonWidget()';