MIT = { 
  Cycling: {
    Core: {
     }
  }
};

// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
/** 
 * Mark every row in a table as odd or even. If iEventClass or iOddClass is not
 * provided, 'even' and 'odd' will be used.  Does not mark rows that have 
 * th (table header) elements in them.
 *
 * @param iTableId - id of a table in the document, a string, required.
 * @param iEvenClass - class name to add to an even row in the table, a string, optional.
 * @param iOddClass - class name to add to an odd row in the table, a string, optional.
 *
 * @return undefined
 */
MIT.Cycling.Core.markEvenOddRows = function(iTableId, iEvenClass, iOddClass) {
 
  //
  // Input checking
  //
  if ( 'string' != typeof(iTableId) ) {
    return;
  }
  if ( 'string' != typeof(iEvenClass) ) { iEvenClass = 'even'; }
  if ( 'string' != typeof(iOddClass) ) { iOddClass = 'odd'; }

  //
  // Setup
  //
  var aTable = document.getElementById(iTableId);
  if ( null === aTable ) {
    return;
  }

  if ( 'table' != aTable.nodeName.toLowerCase() ) {
    return;
  }

  // 
  // Go through each row and mark it as even or odd.  Don't mark rows that
  // have th (table header) elements in them.
  //
  var aCount = 0;
  for ( var i = 0; i < aTable.rows.length; i++ ) {
    var aRow = aTable.rows[i];

    // Look for header elements
    var aHasHeaderElements = false;
    for ( var j = 0; (aHasHeaderElements === false) && (j < aRow.cells.length); j++ ) {
      var aCell = aRow.cells[j];
      if ( 'th' == aCell.nodeName.toLowerCase() ) { 
	aHasHeaderElements = true;
      }
    }

    // Finally, mark the class
    if ( !aHasHeaderElements ) {
      YAHOO.util.Dom.removeClass(aRow, (0 === (aCount%2)) ? iOddClass : iEvenClass);
      YAHOO.util.Dom.addClass(aRow, (0 === (aCount%2)) ? iEvenClass : iOddClass); 
      aCount++;
    }	
  }  
};


// -----------------------------------------------------------------------------
// Utility Stuff
// -----------------------------------------------------------------------------
if (!String.prototype.endsWith) {
  String.prototype.endsWith = function(suffix) {
    var startPos = this.length - suffix.length;
    if (startPos < 0) {
      return false;
    }
    return (this.lastIndexOf(suffix, startPos) == startPos);
  };
}

MIT.Cycling.Core.Class = {

	/**
	 * Adds the given class to the element.  Does not add duplicate class names.
	 */
	Append: function(iElement,iClassName) { 
   	  // Guard against bogus inputs
 	  if(!iElement || !iClassName ) { return; }
	  
	  // Make sure exactly one class was provided
	  var aNames = iClassName.split(" ");
	  if ( aNames.length > 1 || aNames.length === 0 ) { return; }

	  // Make sure we don't append the class name more than once.
	  iClassName = aNames[0];
  	  if( MIT.Cycling.Core.Class.Has(iElement, iClassName) ) { return; }
    
	  if ( iElement ) {
			if ( iElement.className && iElement.className.length > 0 ) {
				iElement.className += " " + iClassName;
			} else {
				iElement.className = iClassName;
			}
		}  
	},
	
	/**
   * Removes the given class name from the element.
   */
	Remove: function (iElement, iClassName) {
		if ( iElement && MIT.Cycling.Core.Class.Has(iElement, iClassName) ) {
			// regexp is: "start of the class name attribute, followed by a word boundry and some number of spaces
			// or zero or more of spaces followed by a word boundry, followed by the class name, followed by a word
			// boundry".  
			iElement.className = iElement.className.replace( new RegExp("^"+iClassName+"\\b\\s*|\\s*\\b"+iClassName+"\\b",'g'),'');
		}
	},

  /** 
   * Returns true if the DOM element has the given class name, false otherwise. 
   */
	Has: function(iElement, iClassName) { 
   	    // Guard against bogus inputs
 	    if(!iElement || !iClassName ) { return false; }
	  
	    // Make sure exactly one class was provided
	    var aNames = iClassName.split(" ");
	    if ( aNames.length > 1 || aNames.length === 0 ) { return false; }

		// Regexp is: a word boundry, followed by the class name, followed by a word boundry
	    return (!iElement || !iElement.className || !iClassName || (iClassName === "")) ? false :
		new RegExp("\\b" + iClassName + "\\b").test(iElement.className);
	}
};

// -----------------------------------------------------------------------------
// Changes the info text at the top of any page that supports it
// -----------------------------------------------------------------------------
// The text shown at the top of the page and randomly cycled through
// if you want to show something different on a page, you can modify this array
// using javascript embedded on the page.
MIT.Cycling.Core.InfoTexts = 
[
  '2008 Track National Champions',
  '2007 National Omnium Champions ',
  '2007 National Womens Team Time Trial Champions',
  '2007 National Road Champions ',
  '2007 ECCC Road Champions',
  '2007 ECCC Cyclocross Champions',
  '2007 National Track Runner-Ups',
  '2007 National Cyclocross Runner-Up',
  '2006 ECCC Road Champions',
  '2006 National Cyclocross Champions',
  '2005 ECCC Road Champions'
];

MIT.Cycling.Core.InfoIndex = 0;

// How quickly the spinner will change
MIT.Cycling.Core.InfoUpdatePeriodMS = 2000;

MIT.Cycling.Core.InfoElement = "uxInfoSpinner";

MIT.Cycling.Core.InfoShow = function() {
  var aInfo = document.getElementById(MIT.Cycling.Core.InfoElement);
  if (aInfo == null ) return;

  // Show the div by removing the style that hid it
  MIT.Cycling.Core.Class.Remove(aInfo, "hidden");
};

MIT.Cycling.Core.InfoUpdate = function() {
  MIT.Cycling.Core.InfoShow();

  var aInfo = document.getElementById(MIT.Cycling.Core.InfoElement);
  if (aInfo == null ) return;

  // Show the next bit of info
  MIT.Cycling.Core.InfoIndex  = (MIT.Cycling.Core.InfoIndex + 1) % MIT.Cycling.Core.InfoTexts.length;
  aInfo.childNodes[0].nodeValue = MIT.Cycling.Core.InfoTexts[MIT.Cycling.Core.InfoIndex];
  setTimeout(MIT.Cycling.Core.InfoUpdate, MIT.Cycling.Core.InfoUpdatePeriodMS);
};