// ==UserScript==
// @name           top 250 tracker
// @namespace      http://bradmont.net
// @include        http://www.imdb.com/chart/top
// @include        http://www.imdb.com/chart/top#
// ==/UserScript==

var total_watched = {};
GM_registerMenuCommand("Change Data Sets", inputDataSetNames);
GM_registerMenuCommand("Add Remote Data Set", inputRemoteDataSetNames);

var NOT_WATCHED = 0; var WATCHED = 1; var TO_WATCH=2; var WONT_WATCH=3; var OWN=4;
var ICON_URLS = new Array("http://bradmont.net/media/img/applications.png", "http://bradmont.net/media/img/check.png", "http://bradmont.net/media/img/add.png", "http://bradmont.net/media/img/close.png", "http://bradmont.net/media/img/have.png", "http://bradmont.net/media/img/own_to_watch.png");


function run() {
   tbodies = document.getElementsByTagName("tbody");
   tbody = tbodies[11]; // the one we want.
   trs = tbody.childNodes;
   addFooter(tbody);

   dataSets = getDataSetNames();
   for (var i = 0; i < dataSets.length; i++){
      addLocalDataSet(dataSets[i], trs);
   }

   remoteDataSets = GM_getValue("remoteDataSets", "");
   if (remoteDataSets != ""){
      addRemoteDataSets(remoteDataSets, trs);
   }
}

function addRemoteDataSets(sets, trs){
   sets = sets.split(",");
   var queries = [];
   for (var i = 0; i < sets.length; i++){ 
      queries.push("q=" + sets[i].replace(/ /, "")); 
   }
   
   GM_xmlhttpRequest({
      method: "GET",
      url: "http://robots.bradmont.net/cgi-bin/imdb_top250.cgi?" + queries.join("&"),
      onload: function(responseDetails){
         data = responseDetails.responseText;
         data = data.split("\n");
         for (var i = 0; i < data.length; i++){
            if (data[i].indexOf("#") != -1) {
               dataSet = data[i].split("#");
               dataSet[1] = eval( '(' + dataSet[1] + ')');
               addDataSet(dataSet[1], dataSet[0], trs, 0);
            }
         }
      }

   });
}

function submitData(dataSet, watched_values){
   url = "http://robots.bradmont.net/cgi-bin/imdb_top250.cgi?" + "user="+dataSet+"&data="+escape(associativeArrayToJson(watched_values));
   GM_xmlhttpRequest({
      method: "GET",
      url: url,
      onload: function(responseDetails){
         if (responseDetails.status != 200){
            alert("Status: Error!\nServer says: "+responseDetails.responseText);
         } else {
            alert("Status: Success!\nServer says: "+responseDetails.responseText);
         }
      }
   });

}

function addLocalDataSet(dataSet, trs){
   var watched_values = getData(dataSet);
   addDataSet(watched_values, dataSet, trs, 1);
}

function addDataSet(watched_values, dataSet, trs, changeable){
   total_watched[dataSet] = 0;
   // add title cell to table header row
   td = document.createElement("td");
   td.setAttribute("style", "font-weight: bold;");
   if (changeable){
      a = document.createElement("a");
      a.setAttribute("href", "#");
      a.setAttribute("title", "Submit data to remote server");
      a.appendChild(document.createTextNode(dataSet.toUpperCase()));
      td.appendChild(a);
      a.addEventListener("click", function() {
         submitData(dataSet, watched_values);
      }, true);
   } else {
      td.appendChild(document.createTextNode(dataSet.toLowerCase()));
   }
   trs[0].appendChild(td);

   for (var i = 1; i < trs.length; i++){
      var id = getID(trs[i]);
      if (id != ""){
         var watched = 0;
         try {
            watched = watched_values[id];
         } catch (e){ alert(e); }
         if (watched == undefined){ watched = 0; }

         if (watched == WATCHED || watched == OWN){
            total_watched[dataSet] += 1;
         }

         td = document.createElement("td");
         img = document.createElement("img");
         img.setAttribute("id", dataSet + "_" + id);
         img.setAttribute("style", "border: 0;");
         img.setAttribute("src", ICON_URLS[watched]);
         if (changeable == 1){
            img.addEventListener("click", lambda(id, dataSet, ICON_URLS.length ), true);
         }
         td.appendChild(img);
         trs[i].appendChild(td);

      } else { // stick the total here.
         td = document.createElement("td"); 
         td.appendChild(document.createTextNode(String(total_watched[dataSet])));
         td.setAttribute("id", "td_total_" + dataSet);
         trs[i].appendChild(td);
      }
   }

}

function associativeArrayToJson(aar){
   var l = Array();
   for (var key in aar){
      l.push('"' + key + '":' + aar[key])
   }
   l = l.sort();
   json = "{" + l.join(", ") + "}";
   return json;
}

function lambda(id, dataSet, mod){
   return function () {
      var watched_values = GM_getValue("watched_values_" + dataSet, "{}");
      watched_values = eval("(" + watched_values + ")"); 

      var data = watched_values[id];
      data += 1;
      data %= mod;
      watched_values[id] = data;
      a = document.getElementById(dataSet + "_" + id);

      // update the picture:
      a.setAttribute("src", ICON_URLS[data]);
      // update the total count:
      if (data == WATCHED || data == OWN){
         total_watched[dataSet] += 1;
         update_total(dataSet);
      } else if ((data == (WATCHED+1) && data != OWN) || (data == ((OWN+1) % mod) && data!=WATCHED)){
         total_watched[dataSet] -= 1;
         update_total(dataSet);
      }

      watched_values = associativeArrayToJson(watched_values);
      GM_setValue("watched_values_" + dataSet, watched_values);
      return false;
   }
}

function getID(tr){
   try {
      var td = tr.childNodes[2];
      var a = td.firstChild.firstChild;
      var href = a.getAttribute("href");
      var id = href.split("/")[2];
      return id;
   } catch (e) {
      return "";
   }
}

function update_total(dataSet){
   td = document.getElementById("td_total_"+dataSet);
   td.innerHTML = String(total_watched[dataSet]);
}

function addFooter(tbody){
   // add footer row
   tr = document.createElement("tr");
   tr.setAttribute("style", "background-color: #e5e5e5; font-weight: bold;");
   td = document.createElement("td"); tr.appendChild(td);
   td = document.createElement("td"); tr.appendChild(td);
   td = document.createElement("td"); tr.appendChild(td);
   td.appendChild(document.createTextNode("Total"));
   td = document.createElement("td"); tr.appendChild(td);
   td = document.createElement("td"); 
   tbody.appendChild(tr);
}

function getData(dataSet){
   var watched_values = GM_getValue("watched_values_" + dataSet, "{}");
   if (watched_values == "{}"){
      watched_values = getOldData();
      GM_setValue("watched_values_"+dataSet, watched_values);
   }
   watched_values = eval("(" + watched_values + ")"); // parentheses to fix "invalid label" error.
   return watched_values;
}

function getOldData() {
   // we're now storing all data in one variable; this will grab
   // the old multivariable data and convert it to the new format
   // if data in the new format is not found.
   tbodies = document.getElementsByTagName("tbody");
   tbody = tbodies[11]; // the one we want.

   trs = tbody.childNodes;

   var aar = "{";
   for (var i = 1; i < trs.length; i++){
      var id = getID(trs[i]);
      var watched = GM_getValue("watched" + id, 0);
      aar += '"' + id + '":' + watched;
      if (i < trs.length-1) {
         aar += ", ";
      }

   }
   aar += "}";
   return aar;
}
function inputDataSetNames(){
   var sets = GM_getValue("dataSets", "");
   sets = prompt("Enter dataSet names, separated by commas (eg: AA, BB)", sets);
   GM_setValue("dataSets", sets);
   return sets;
}

function inputRemoteDataSetNames(){
   var sets = GM_getValue("remoteDataSets", "");
   sets = prompt("Enter dataSet names, separated by commas (eg: AA, BB)", sets);
   GM_setValue("remoteDataSets", sets);
   if (remoteDataSets != ""){
      addRemoteDataSets(remoteDataSets);
   }
}

function getDataSetNames(){
   var sets = GM_getValue("dataSets", "");
   if (sets == ""){
      sets = inputDataSetNames();
   }
   sets = sets.split(",");
   for (var i = 0; i < sets.length; i++){ sets[i] = sets[i].replace(/ /, ""); }
   return sets;
}

run();
