// cyclingnews_com
// $Id: cyclingnews_com.user.js 17 2009-07-12 06:42:11Z mike $
// Copyright (c) 2005-2006, Michael Strasser
// Released under the GPL license
// http://www.gnu.org/copyleft/gpl.html
//
// --------------------------------------------------------------------
//
// This is a Greasemonkey user script.
//
// To install, you need Greasemonkey: http://greasemonkey.mozdev.org/
// Then restart Firefox and revisit this script.
// Under Tools, there will be a new menu item to "Install User Script".
// Accept the default configuration and install.
//
// To uninstall, go to Tools/Manage User Scripts,
// select "cyclingnews_com", and click Uninstall.
//
// --------------------------------------------------------------------
//
// ==UserScript==
// @name          cyclingnews_com
// @namespace     http://michaelstrasser.com/greasemonkey/
// @description   Utilities for cyclingnews.com.
// @include       http://*.cyclingnews.com/*
// ==/UserScript==
//
// --------------------------------------------------------------------

// Object for styling text in a page.
function Styler(pat, cls, css) {
  // Regular expression to match.
  this.re = new RegExp(pat, "ig");
  // Name of the CSS class that will be applied to the matched text.
  this.cls = cls;
  // CSS to be applied to that class.
  this.css = css;
}

// Populate an array of Styler objects.
var stylers = [
  // Team styles. These are the teams in the 2009 Tour de France.
  // Abbreviations are the official UCI abbreviations for the teams.
  new Styler(
    "AG2R ?-?La Mondiale",
    "ALM",
    "background-color: #FFFFFF; color: #610016; border: 2px solid #00B3E5;"  
  ),
  new Styler(
    "Agritubel",
    "AGR",
    "background-color: #0051A7; color: #FFFFFF; border: 2px solid #008CD7;"
  ),
  new Styler(
    "Astana",
    "AST",
    "background-color: #40DBF5; color: #00397F; border: 2px solid #FFD600;"  
  ),
  new Styler(
    "BBOX Bouygues Telecom",
    "BBO",
    "background-color: #0092B6; color: #FFFFFF; border: 2px solid #0050A7;"
  ),
  new Styler(
    "Caisse d'Epargne",
    "GCE",
    "background-color: #FF0000; color: #FFFFFF; border: 2px solid #000000;"  
  ),
  new Styler(
    "Cervelo Test Team",
    "CTT",
    "background-color: #FFFFFF; color: #000000; border: 2px solid #000000;"  
  ),
  new Styler(
    "Cofidis,? Le Cr[eé]dit en Ligne",
    "COF",
    "background-color: #FF001D; color: #FFFFFF; border: 2px solid #FFBC00;"
  ),
  new Styler(
    "Euskaltel - Euskadi",
    "EUS",
    "background-color: #FD6325; color: #FFFFFF; border: 2px solid #00803F;"
  ),
  new Styler(
    "Fran.aise Des Jeux",
    "FDJ",
    "background-color: #EEEEEE; color: #004991; border: 2px solid #FF0028;"  
  ),
  new Styler(
    "Garmin - Slipstream",
    "GRM",
    "background-color: #FFFFFF; color: #000000; border: 2px solid #FF9500;"
  ),
  new Styler(
    "Lampre - N.?G.?C",
    "LAM",
    "background-color: #305FB3; color: #FFFFFF; border: 2px solid #FF37A1;"
  ),
  new Styler(
    "Liquigas",
    "LIQ",
    "background-color: #B7DE68; color: #1A438D; border: 2px solid #B7DE68; text-transform: uppercase; font-weight: bold;"
  ),
  new Styler(
    "Quick Step",
    "QST",
    "background-color: #0052A8; color: #FFFFFF; border: 2px solid #0052A8; text-transform: uppercase;"
  ),
  new Styler(
    "Rabobank",
    "RAB",
    "background-color: #FF8A00; color: #302A8D; border: 2px solid #FF8A00;"
  ),
  new Styler(
    "Silence ?- ?Lotto",
    "SIL",
    "background-color: #642298; color: #FFFFFF; border: 2px solid #FD0022;"
  ),
  new Styler(
    "Skil-Shimano",
    "SKS",
    "background-color: #FFFFFF; color: #FF0000; border: 2px dashed #FF0000; font-weight: bold;"
  ),
  new Styler(
    "Team Columbia ?- ?HTC",
    "THR",
    "background-color: #FFFF00; color: #000000; border: 2px solid #000000;"
  ),
  new Styler(
    "Team Katusha",
    "KAT",
    "background-color: #FFFFFF; color: #0E2769; border: 2px solid #FF0000;"
  ),
  new Styler(
    "Team Milram",
    "MRM",
    "background-color: #00B7EB; color: #FFFFFF; border: 2px solid #00B7EB;"
  ),
  new Styler(
    "Team Saxo Bank",
    "SAX",
    "background-color: #0E388D; color: #FFFFFF; border: 2px solid #000000;"
  ),
  // Women’s teams.
  new Styler(
    "Australian national team",
    "ANT",
    "background-color: #FFFF66; color: #006600;"
  ),
  new Styler(
    "(Equipe )?N(ü|ue)rnberger Versicherung",
    "NBV",
    "background-color: #3F68D7; color: #FFFFFF;"
  ),
  new Styler(
    "Austrian national team",
    "AUT",
    "background-color: #CC3333; color: #FFFFFF;"
  ),
  // Riders names and their countries.
  new Styler(
    "\\(Aus(tralia)?\\)",
    "AUS",
    "background-color: #FFFF66; color: #006600; font-weight: bold;"
  )
];

// Apply these styles to matched text in <pre> elements in this page.
// There are two steps:
//    1.  Write a style element with CSS class definitions.
//    2.  Match text in <pre> elements and replace them with
//        styled versions of the same text.
function applyStyles() {
  var css, s, styler, head, style, pres, p, pre, html;
  // ----------------------------------------------------------------
  // 1. Write a style element into the document head.
  // ----------------------------------------------------------------
  // Write a class entry for each style.
  css = "";
  for (s = 0; s < stylers.length; ++s) {
    styler = stylers[s];
    css += "span." + styler.cls + " { " + styler.css + " }\n";
  }
  // Style element is last in the head element.
  head = document.getElementsByTagName("head")[0];
  if (! head) return;
  style = document.createElement("style");
  style.type = "text/css";
  style.innerHTML = css;
  head.appendChild(style);
  // ----------------------------------------------------------------
  // 2. Find the text and apply the styles.
  // ----------------------------------------------------------------
  // Result information is all in tables in "results" divs.
  var riders = document.evaluate(
      "//div[@class='results']/table/tbody/tr/td",
      document,
      null,
      XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
      null
  );
  for (var r = 0; r < riders.snapshotLength; ++r) {
    var rider = riders.snapshotItem(r);
    html = rider.innerHTML;
    // Replace the searched-for text with a styled version of it.
    for (s = 0; s < stylers.length; ++s) {
      styler = stylers[s];
      html = html.replace(
        styler.re,
        "<span class='" + styler.cls + "'>&nbsp;$&&nbsp;</span>"
      );
    }
    rider.innerHTML = html;
  }
}

// Go to the link whose text is specified.
function goLink(regex) {
  
  var anchors = document.evaluate(
      "//a",
      document,
      null,
      XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
      null
  );
  for (var i = 0; i < anchors.snapshotLength; ++i) {
    var anchor = anchors.snapshotItem(i);
    if (anchor.innerHTML.match(regex)) {
      window.location.href = anchor.href;
    }
  }
}

function handleKeyPress(e) {
  if (! e.ctrlKey) {
    switch (e.which) {
    case 102: // f: go to focus named anchor.
      window.location.href = window.location.href + "#focus";
      break;
    case 104: // h: go to the home page
      window.location.href = "http://www.cyclingnews.com/"; // back to home page
      break;
    case 110: // n: go to the next photo or news story or stage
      goLink(/Next\s+(photo|news|stage)/ig);
      break;
    case 111: // o: go to overall named anchor.
      window.location.href = window.location.href + "#gcOverall";
      break;
    case 112: // p: go to the previous photo or news story or stage
      goLink(/Previous\s+(photo|news|stage)/ig);
      break;
    case 114: // r: go to the related story or the to results on this page.
      goLink(/Related\s+Story/ig);
      // Using goLink() here produces strange results.
      window.location.href = window.location.href + "#res";
      break;
    }
  }
}

// Add a named anchor to the main photo on this page.
function addPhotoAnchor() {
  var result = document.evaluate(
      "//div[@id='content_main']/a",
      document,
      null,
      XPathResult.FIRST_ORDERED_NODE_TYPE,
      null
  );
  if (result) {
    var newAnchor = document.createElement("a");
    newAnchor.name = "focus";
    var anchor = result.singleNodeValue;
    anchor.parentNode.insertBefore(newAnchor, anchor);    
  }
}

function addStandingsAnchor() {
  var captions = document.evaluate(
      "//div[@class='results']/table/caption[starts-with(.,'General classification after')]",
      document,
      null,
      XPathResult.FIRST_ORDERED_NODE_TYPE,
      null
  );
  if (captions) {
    var anchor = document.createElement("a");
    anchor.name = "gcOverall";
    var caption = captions.singleNodeValue;
    caption.parentNode.insertBefore(anchor, caption);
  }
}

(function() {

    // Apply styling to race results.
    applyStyles();
    
    // Handle key presses.
    document.addEventListener('keypress', handleKeyPress, true);

    // Add named anchors to photos in photo pages.
    if (window.location.href.indexOf("/photos/") > -1) {
      addPhotoAnchor();
    }
    
    // Add overall standings link to results pages.
    if (window.location.href.indexOf("/results") > -1) {
      addStandingsAnchor();
    }

})();
