utils = {
 browserInfo: {
  matches: {
    webKit: navigator.userAgent.match(/AppleWebKit\/(\d+)/),
    opera: navigator.userAgent.match(/^Opera\/(\d+\.\d+)/),
    mozilla: navigator.userAgent.match(/^Mozilla\/(\d+\.\d+).*\srv:(\d+\.\d+)/)
  }
 },

 firstLast: { row: ["firstRow", "lastRow"], cell: ["firstCell", "lastCell"] },

 regex: {
  hasRows: /\bhasRows\b/,
  zebraRows: /\bzebraRows\b/,
  row: /\brow\b/,
  cell: /\bcell\b/,
  headerRow: /\bheaderRow\b/,
  hidden: /\bhidden\b/,
  remove1: /^.+\(.*\).+$/,
  remove2: /^\(.+\)$/,
  evenOdd: /\b(even|odd)\b/,
  evenOddRemove: /(^\s*)?(\s*?)\b(even|odd)\b(\s*$)?(\s*)?/,
  stripFirstLastRow: /(^\s*)?(\s*?)\b(firstRow|lastRow)\b(\s*$)?(\s*)?/,
  stripFirstLastCell: /(^\s*)?(\s*?)\b(firstCell|lastCell)\b(\s*$)?(\s*)?/
 },

 strip: function(stripRegex, inString) {
    return(inString.replace(stripRegex, function() { var a=arguments; if((typeof(a[2]) == "undefined") || (typeof(a[5]) == "undefined")) { return(""); } return((a[2].length > 0) && (a[5].length > 0) ? " ":""); } ));
  }
};


utils.browserInfo.webKit = (utils.browserInfo.matches.webKit != null) ? true : false;
if(utils.browserInfo.webKit == true) { utils.browserInfo.webKitVersion = utils.browserInfo.matches.webKit[1]; }

utils.browserInfo.opera = (utils.browserInfo.matches.opera != null) ? true : false;
if(utils.browserInfo.opera == true) { utils.browserInfo.operaVersion = utils.browserInfo.matches.opera[1]; }

utils.browserInfo.mozilla = (utils.browserInfo.matches.mozilla != null) ? true : false;
if(utils.browserInfo.mozilla == true) { utils.browserInfo.mozillaVersion = utils.browserInfo.matches.mozilla[1]; utils.browserInfo.geckoVersion = utils.browserInfo.matches.mozilla[2]; }

function fixupBoxRows () {
  var boxesWithRowsArray = getElementsByClassWithRegex(utils.regex.hasRows);
  for(var x=0; x<boxesWithRowsArray.length; x++) {
    fixupFirstLastRowsAndCellsWithBox(boxesWithRowsArray[x]);
    if(boxesWithRowsArray[x].className.search(utils.regex.zebraRows) != -1) { fixupZebraRowsBox(boxesWithRowsArray[x]); }
  }
}

function fixupFirstLastRowsAndCellsWithBox(boxWithRowsAndCells) {
  var rowArray = boxWithRowsAndCells.childNodes;

  fixupFirstLastClassArray(rowArray, utils.regex.stripFirstLastRow, utils.regex.row, utils.firstLast.row);
  for(var x=0; x<rowArray.length; x++) {
    if(rowArray[x].nodeType != 1) { continue; }
    if(rowArray[x].className.search(utils.regex.row) == -1) { continue; }
    fixupFirstLastClassArray(rowArray[x].childNodes, utils.regex.stripFirstLastCell, utils.regex.cell, utils.firstLast.cell);
  }
}

function fixupFirstLastClassArray(elementArray, stripRegex, classRegex, firstLastArray) {
  var firstVisibleElement = null, lastVisibleElement = null;

  for(var x=0; x<elementArray.length; x++) {
    if(elementArray[x].nodeType != 1) { continue; }

    elementArray[x].className = utils.strip(stripRegex, elementArray[x].className);
    if(isElementWithClassRegexVisible(elementArray[x], classRegex) == null) { continue; }
    if(firstVisibleElement == null) { firstVisibleElement = elementArray[x]; }
    lastVisibleElement = elementArray[x];
  }
  if(firstVisibleElement != null) { firstVisibleElement.className = firstVisibleElement.className + " " + firstLastArray[0]; }
  if(lastVisibleElement  != null) { lastVisibleElement.className  = lastVisibleElement.className  + " " + firstLastArray[1];  }
}

function fixupZebraRowsBox(zebraBox) {
  var childArray = zebraBox.childNodes, evenOddCount = 1;

  for(var x=0; x<childArray.length; x++) {
    if(childArray[x].nodeType != 1) { continue; }
    if(childArray[x].className.search(utils.regex.row) == -1) { continue; }
    if((childArray[x].className.search(utils.regex.headerRow) != -1) || (isElementWithClassRegexVisible(childArray[x], utils.regex.row) == null)) {
      childArray[x].className = utils.strip(utils.regex.evenOddRemove, childArray[x].className);
      continue;
    }
    childArray[x].className = childArray[x].className.replace(utils.regex.evenOdd, ((evenOddCount%2) == 1) ? "odd":"even");
    evenOddCount++;
  }
}

function isElementWithClassRegexVisible(element, classRegex) {
  if((element.className.search(classRegex) == -1) || (element.className.search(utils.regex.hidden) != -1)) { return(null); }
  if(typeof(element.scrollWidth) == "undefined") { return(null); }
  if((element.scrollWidth != 0) && (element.scrollHeight != 0)) { return(element); }
  if((utils.browserInfo.webKit == true) && (utils.browserInfo.webKitVersion < 522)) { return(element); }
  return(null);
}

function getElementsByClassWithRegex(withRegex) {
  var matchedElementsArray = new Array(), elementArray = document.getElementsByTagName("*");
  for(var i = 0; i < elementArray.length; i++) { if(elementArray[i].className.search(withRegex) != -1) { matchedElementsArray.push(elementArray[i]); } }
  return(matchedElementsArray);
}

addEventListener("load", fixupBoxRows, false);

