// update: 
// turns out, these guys do a much better job of the twitter
// integration: http://github.com/seaofclouds/tweet/blob/master/tweet/jquery.tweet.js
// there are also similar things for delicious; cf, eg:
// http://code.google.com/p/jqueryjs/source/browse/trunk/plugins/delicious/jquery.delicious.js
//
//-------------------------------------------------------------
// misc stuff
//
var items = new Array();
var datasetsLoaded = 0;

// called when data loads
function dataReady() {
  datasetsLoaded++;
  if (datasetsLoaded > 1) {
    items.sort(timestampCompare);
    var container = $('#itemContainer');
    $.each(items, function(i,item){
      item.insertNode(container);
    });
  }
}

function loadDelicious() {
  $.getJSON("http://feeds.delicious.com/v2/json/emerose?count=100&callback=?", function(data){
    $.each(data, function(i,item){
      var ni = new DeliciousItem(item);
      items.push(ni);
    });
    dataReady();
  });
}

function loadTwitter() {
  $.getJSON("http://twitter.com/status/user_timeline/emerose.json?count=100&callback=?", function(data){
    $.each(data, function(i,item){
      var ts = new Date();
      if (!item.in_reply_to_screen_name) {  // don't display my replies to others
        var ni = new TwitterItem(item);
        items.push(ni);
      }
    });
    dataReady();
  });
}

// useful for sorting Items in rev-chron order
function timestampCompare(a,b) {
  return b.timestamp.valueOf() - a.timestamp.valueOf();
}

$(document).ready(function() {
  loadDelicious();
  loadTwitter();
});

//-------------------------------------------------------------
// *Item objects
//
function DeliciousItem(item) {
  this.type  = "delicious";
  this.title = item.d.quotify();
  this.url   = item.u;
  this.html  = item.n.quotify().linkify();
  this.timestamp = new Date();
  this.timestamp.parse8601(item.dt);
  this.node      = null;
};

DeliciousItem.prototype.createNode = function() {
  this.node = $('<div class="deliciousItem"></div>');
  var title    = $('<a class="deliciousTitle" />').html(this.title).attr("href", this.url);
  var desc     = $('<div class="deliciousDesc"></div>').html(this.html);
  var meta     = $('<p class="deliciousMeta"></p>').text(this.timestamp.humanReadableString());
  this.node.append(title).append(desc).append(meta);
  return this.node;
}

DeliciousItem.prototype.insertNode = function(where) {
  if (!this.node) { this.createNode(); }
  where.append(this.node);
}

function TwitterItem(item) {
  this.type = "twitter";
  this.url  = "http://twitter.com/emerose/status/" + item.id;
  this.html = item.text.quotify().linkify().atify();
  this.timestamp = new Date();
  this.timestamp.parseRubyTime(item.created_at);
};

TwitterItem.prototype.createNode = function() {
  this.node = $('<div class="twitterItem"></div>');
  var text  = $('<div class="twitterText"></div>').html(this.html);
  var meta  = $('<p class="twitterMeta"></p>');
  var link  = $('<a/>').text(this.timestamp.humanReadableString()).attr("href", this.url);
  meta.append(link);
  this.node.append(text).append(meta);
  return this.node;
}

TwitterItem.prototype.insertNode = function(where) {
  if (!this.node) { this.createNode(); }
  where.append(this.node);
}

//-------------------------------------------------------------
// Extensions to Date object
//
// thanks to paul sowden
// http://delete.me.uk/2005/03/iso8601.html
Date.prototype.parse8601 = function(string) {
  var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
    "(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" +
    "(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
  var d = string.match(new RegExp(regexp));

  var offset = 0;
  var date = new Date(d[1], 0, 1);

  if (d[3]) { date.setMonth(d[3] - 1); }
  if (d[5]) { date.setDate(d[5]); }
  if (d[7]) { date.setHours(d[7]); }
  if (d[8]) { date.setMinutes(d[8]); }
  if (d[10]) { date.setSeconds(d[10]); }
  if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
  if (d[14]) {
    offset = (Number(d[16]) * 60) + Number(d[17]);
    offset *= ((d[15] == '-') ? 1 : -1);
  }

  offset -= date.getTimezoneOffset();
  this.setTime(Number(date) + (offset * 60 * 1000));
  return this;
}

// As above, but for ruby timestamps.
// Other folks seem to make do with the native Date.parse,
// but I've been having problems with that on Safari 4.
// Ruby's time strings look like this:
// 'Thu Oct 01 00:40:50 +0000 2009'
Date.prototype.parseRubyTime = function(string) {
  var date_elts = string.split(" ");
  var time_elts = date_elts[3].split(":");
  var monthLookup = {
    "Jan": 0,
    "Feb": 1,
    "Mar": 2,
    "Apr": 3,
    "May": 4,
    "Jun": 5,
    "Jul": 6,
    "Aug": 7,
    "Sep": 8,
    "Oct": 9,
    "Nov": 10,
    "Dec": 11
  }

  var offset = 0;
  var date = new Date(date_elts[5], 0, 1);

  date.setMonth(monthLookup[date_elts[1]]);
  date.setDate(date_elts[2]);
  date.setHours(time_elts[0]);
  date.setMinutes(time_elts[1]);
  date.setSeconds(time_elts[2]);

  // this will be wrong for folks with funky timezones
  // (half hours and such).  shrug.
  var hourOffset = Number(date_elts[4].substr(1,2)) * 6 / 10;
  var minOffset  = Number(date_elts[4].substr(3,2));
  var offsetSign = ((date_elts[4].substr(0,1) == '+') ? 1 : -1);

  offset = offsetSign * (hourOffset + minOffset);

  offset -= date.getTimezoneOffset();
  this.setTime(Number(date) + (offset * 60 * 1000));
  return this;
}

Date.prototype.humanReadableString = function() {
  var now = new Date();
  var timeAgo = (now.getTime() - this.getTime()) / 1000; // in seconds, not ms

  var date_elts = this.toLocaleString().split(" ");
  var month     = date_elts[0];
  var day       = date_elts[1].substr(0,date_elts[1].length); // chop off the comma
  var year      = date_elts[2];
  var time      = date_elts[3];
  var ampm      = date_elts[4];
  var tz        = date_elts[5];

  var time_elts = time.split(":");
  var hour      = time_elts[0];
  var min       = time_elts[1];
  var sec       = time_elts[2];

  // the date at midnight this morning:
  var thisMorning = new Date();
  thisMorning.setHours(0);
  thisMorning.setMinutes(0);
  thisMorning.setSeconds(0);
  thisMorning.setMilliseconds(0);

  var timeSinceThisMorning = (thisMorning.getTime() - this.getTime()) / 1000; 

  var dayLookup = { 
    0: "Sunday",
    1: "Monday",
    2: "Tuesday",
    3: "Wednesday",
    4: "Thursday",
    5: "Friday",
    6: "Saturday"
  };

  if (timeSinceThisMorning > 604800) { // >7 days: "September 30 at 11:33 PM"
    return month + " " + day + " at " + hour + ":" + min + " " + ampm;
  }
  if (timeSinceThisMorning > 86400) { // >1 day ago: "Tuesday at 12:34 PM"
    return dayLookup[this.getDay()] + " at " + hour + ":" + min + " " + ampm;
  }
  if (timeSinceThisMorning > 0) {     // Yesterday: "Yesterday at 12:34 PM"
    return "Yesterday at " + hour + ":" + min + " " + ampm;
  }
  if (timeAgo > 3600) { // >1 hour: "About 3 hours ago"
    return "About " + Math.round(timeAgo / 3600) + " hours ago";
  }
  if (timeAgo > 60) { // >1 minute: "43 minutes ago"
    return Math.round(timeAgo / 60) + " minutes ago";
  }
  return "Just now";
}

String.prototype.linkify = function() {
  var urlRegex = new RegExp(
      '((https?|ftp):\/\/|www\.)' +    // either a protocol or 'www.' is required
                                       // user:pass@ URLs are not supported
      '[a-z0-9-_\.]+' +                // the rest of the host name
      '(:[0-9]+)?' +                   // port number, optional
      '(\/[a-z0-9#!:.?+=&%@!\-\/]*)?', // path, query string, etc; all optional
    'gi');

  var ret = this.replace(urlRegex, function(m) {
    // see if it has a protocol attached:
    var fullyFormed = m.match(/(https?|ftp):\/\//);

    if (fullyFormed) {
      return '<a href="' + m + '">' + m + '</a>';
    } else {
      return '<a href="http://' + m + '">' + m + '</a>';
    }
  });

  return ret;
}

String.prototype.atify = function() {
  var atRegex = /@([a-z0-9-_]+)/gi;
  return this.replace(atRegex, "<a href=\"http://twitter.com/$1\">@$1</a>");
}

String.prototype.hashify = function() {
  var atRegex = /#([a-z0-9-_]+)/gi;
  return this.replace(atRegex, "<a href=\"http://search.twitter.com/search?q=%23$1\">#$1</a>");
}

// I should really just reimplement smartypants in JS...
String.prototype.quotify = function() {
  var doubleQuoteLevel = 0;
  var i;
  var ret = "";

  for (i = 0; i < this.length; i++) {
    if (this.charAt(i) == '"') {
      if (doubleQuoteLevel % 2) {
        ret = ret + "&#8221;"; // right double quote
      } else {
        ret = ret + "&#8220;"; // left double quote
      }
      doubleQuoteLevel++;
    } else if (this.charAt(i) == "'") {
      ret = ret + "&#8217;"; // right single quote
    } else {
      ret = ret + this.charAt(i);
    }
  }
  return ret;
}
