// ==UserScript==
// @name          aTechtalk
// @namespace     http://www.technologyreview.com/
// @include       http://*.com/*
// @include       http://*.nytimes.com/*
// @include       http://*.*.com/*
// @include       file:*.html
// @description   Make it easier to understand the news.
// @exclude

// ==/UserScript==

//GM_log("Running for URL: " + location.href);        

var defaultMatchTable = {
  "Boston Herald":"Harried",
  "Boston Globe":"Boston Glob",
  "Chronicle":"Comical",
  "Times":"Slime",
  "Journal":"Urinal", 
  "Microsoft":"/\/\1cr0$0ph+",
  "Google":"God",
  "Continental":"Colonial", 
  "Republican":"Elephant",
  "Democratic":"Donkey",
  "Justice":"Coin Flipper",
  "Star Wars":"St*r Warz",
  "U.S.":"Uncle Sam",
  "network":"matrix",
  " world":" matrix",
  "senate":"imperial senate",
  "congress":"imperial caucus",
  "World":"Playpen",
  "Washington":"Trantor",
  " answer":" 42",
  "Idaho":"Tater Country",
  "contact us":"exchange fluids with us",
  "contact":"exchange fluids with",
  "sports":"jocks stuff",
  "business":"scandal",
  "interactive":"mouse clicking",
  "video":"eye candy",
  "debate":"food fights",
  "cool":"kewl",
  "news":"snooze",
  "hackers":"h4xx0rz",
  "hacker":"h4xx0r",
  "hacks":"h4x",
  "elite":"1337",
  "user":"luser",
  "porn":"pr0n",
  "vulnerabilities":"sploitz",
  "leet":"1337",
  "terror":"kindness",
  "skills":"mad sk1llz",
  "owners":"pwnz0rz",
  "warez":"w4r3z",
  "lawyer":"law monkey",
  "freedom":"slavery",
  "good":"bad",
  "cloning":"clowning",
  "resign":"get a life",
  "Springsteen":"the boss",
  "science":"alchemy",
  "scientist":"alchemist",
  "travel":"quest",
  "weather":"dryness",
  "shopping":"money wasting",
  "MIT":"IHTFP",
  "arts":"crafts",
  "Hamlet":"Dark Prince",
  "Shakespeare":"Old English Writer Dude",
  "alumni":"suckers",
  "faculty":"tenured deadwood",
  "Harvard":"Halfhard",
  "Stanford":"Palo Alto Community College",
  "Berkeley":"Berzerkly",
  "privacy":"privacy is dead --eds.",
  "DVD":"matchbook",
  "Sign in":"Give us all your secrets",
  "gifts":"porn",
  "MSN":"Looser Town",
  "Windows":"W1nd0ze",
  "XP":"PX",
  " work":" hell",
  "at work":"in hell",
  "At Work":"In Hell",
  "Work":"Hell",
  "citizen":"hostage",
  "partner":"spouse",
  "apple":"peach",
  "Massachusetts":"Taxachusetts",
  "Dell":"D311",
  " terms":" commandments",
  "Palm":"Pain",
  "summit":"junket",
  "doctor":"quack",
  "legal":"arbitrary",
  "speaking":"spitting",
  " break":" build",
  "nuclear":"nukuler",
  "sensitivity":"political correctness",
  "understand":"grok"};

//
// Use XPath to find all text nodes not inside <style> or <script> elements.
//
function processDocument() {
  var textNodes = document.evaluate(
    '//text()[not(ancestor::script) and not(ancestor::style) and ' + 
    'not(ancestor::SCRIPT) and not(ancestor::STYLE)]',
    document,
    null,
    XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
    null);
 
  for (var i = 0; i < textNodes.snapshotLength; i++) {
    processNode(textNodes.snapshotItem(i));
  }
}

//
// Relace occurrences of any of the keys from matchTable with the 
// corresponding values. Make sure to check for capitialization cases as well.
//
function processNode(node) {
  // don't bother with whitespace-only nodes
  if (!node.nodeValue.match(/\S/)) {
    return;
  }
  
  //GM_log("searching: " + node.nodeValue)

  var s = node.nodeValue;
  
  for (var key in matchTable) {
    s = s.replace(key, matchTable[key]);
    s = s.replace(key.toUpperCase(), matchTable[key].toUpperCase());
    s = s.replace(capitalizeInitial(key), capitalizeInitial(matchTable[key]));
  } 
  
  // reset the node's text
  node.nodeValue = s;
}

// 
// Asks the user for a new mapping and adds it to the default matchTable
//
function promptForNewMapping(){
  var newOne = prompt("Enter a new mapping in the format: original=replacement.");
   
  if (!newOne) { 
    return;
  } else {
    newOne = newOne.split("=");
  }
  
  if (newOne.length != 2) {
    return;
  }
  
  GM_log("adding word: " + newOne.join("="));
  
  matchTable[newOne[0]] = newOne[1];
  GM_setValue("matchTable2", uneval(matchTable));
}


function capitalizeInitial(s) {
  return s.charAt(0).toUpperCase()+s.substring(1);
}


//
// Load match table from preference. If it doesn't exist (this is the first
// time this script has run) save it in preferences. We use eval/uneval to
// serialize/deserialize the table.
// 

var matchTable = eval(GM_getValue("matchTable2", null));

if (!matchTable) {
  //GM_log("matchTable not found in prefs, creating")
  // use default and store default in prefs
  matchTable = defaultMatchTable;
  GM_setValue("matchTable2", uneval(defaultMatchTable));
  processDocument();
}

//
// Register a Greasemonkey menu command to add new mappings to matchTable
//
GM_registerMenuCommand("Add a new replacement mapping", promptForNewMapping);

//
// This code links the recursive tree replacement
// function with the page loader. Every page that
// fits the patterns defined in the header will 
// be given the text replacement treatment.
//
window.addEventListener("load", function() {  
  //GM_log("loading...");
  processDocument(); 
}, false);

