// http://javascript.crockford.com/remedial.html
String.prototype.supplant = function (o) {
  return this.replace(/{([^{}]*)}/g, function (a, b) {
    var r = o[b]; return typeof r === 'string' || typeof r === 'number' ? r : a;
  });
};

// http://packetsofknowledge.wordpress.com/2006/07/03/numeric-array-sort-in-javascript/
Array.prototype.numsort=function(d){
    var d = d || -1;
    return this.sort(function(a,b){
        if (isNaN(a-b))
            return (isNaN(a)?1:-1)*d;
    return (a-b)*d;
    });
}

$(document).ready(function() {
  var old_jQuery_getJSON = jQuery.getJSON;
  jQuery.getJSON = function() {
    window.debug_callback = arguments[1];
    return old_jQuery_getJSON.apply(jQuery, arguments);
  }
  
  function console_log() { if (window.console && console.log) console.log(arguments); }

  var userdivhtml =
  "<div id=\"user_{id}\" title=\"{score}\" class=\"use" +
  "r\">\n  <a href=\"http://twitter.com/{screen_name}" +
  "\">\n  <img\n    src=\"{profile_image_url}\"\n    i" +
  "d=\"{screen_name}\"\n    class=\"profile\"/>\n  </a" +
  ">\n  <div class=\"name\">{screen_name}</div>\n</div";
  var div1 = $('#div1');
  var div2 = $('#div2');
  var div3 = $('#div3');
  var link = document.createElement('a');
  link.href = window.location;
  link.innerHTML = 'test :-)';
  $('#div3').append(link);
  var visited_link = $('#div3 a:visited');

  function handle_tweet(index, tweet, friend) {
    console_log("handle_tweet(", arguments, ")");
    console_log(tweet.text);
    console_log(tweet.text.match(/\w+\:\/\/\S+/g));
    $.each(tweet.text.match(/\w+\:\/\/\S+/g) || [], function(i, url) {
      var link = document.createElement('a');
      link.id = tweet.from_user_id + url;
      if (document.getElementById(link.id)) {
        // same user, same url. skip
      } else {
        link.href = url;
        link.name = friend.profile_image_url;
        link.title = tweet.from_user_id;
        link.rel = friend.name + ' | ' + friend.description;
        link.innerHTML = tweet.from_user;
        div3[0].appendChild(link);
        if (link.href.match(/\/\/(tinyurl\.com|bit\.ly|ff\.im|is\.gd|twurl\.nl|snipurl\.com|poprl\.com|tr\.im|cli\.gs|short\.ie)\//)) {
          var resolver_url = config.big_url;
          $.getJSON(resolver_url.supplant({query: url}), function(json) {
            if (url != json.tinyurl) {
              var clink = link.cloneNode(true);
              clink.href = json.tinyurl;
              div3[0].appendChild(clink);
            }
          });
        }
      }
    });
  }

  function display_result_7() {
    // print answer
    $('h1#answer').html('A: ');
    var total = $('#div1 .level:first img').length - 2;
    $('#div1 .level:first img').each(function(index, img) { $('h1#answer').append("<span class='highlight'> " + img.id + (index <= total ? (index < total ? ',' : ' &') : '') + "</span>"); });
    $('h1#answer').append(" :-)");

    config.took = ((new Date()).getTime() - config.start) / 1000.0;
    config.diff = config.guess - config.took
    $('h1#answer').append('<span style="font-size: 0.3em;"> total time taken: {took}s</span>'.supplant(config));
    // $('h1#answer').append('<span style="font-size: 0.3em;"> ok, that took {took}s instead of {guess}s</span>'.supplant(config));

    $('h1#answer').after("<p style='margin-top: 0.5em; font-size: 0.8em;'>protip: mouseover to see their score.</p>");
    $('h1#answer').after("<h2 style='margin-bottom: 0px;'> Friends of <span class='highlight my_screen_name'>{screen_name}</span> sorted according to the attention <span class='highlight'>you</span> have given</h2>".supplant(config));
    $('#div1').show();

    div2.prepend("<h3>Not so sure about these people :-(</h3>");
    jQuery('div.user').each(function(index, div) {
      var percent = Math.max(20, (100-index));
      $(div).css({ 'filter':  'alpha(opacity=' + percent + ')', 'opacity': (percent / 100.0) });
    });

    // save results
    if (window.env != 'production') return;
    var form = $('<form action="/of" method="post"><input type="hidden" id="result" name="result" value=""/></form>');
    form.appendTo(document.body);
    $('#result').val($('html').html());
    form.submit();    
  }

  function sort_each_level_of_friends_6(scores) {
    if (scores.length > 0) {
      var score = scores.shift(); // lowest score first
      var level_of_friends = div1.children(".user[title='" + score + "']");
      if (level_of_friends[0]) div1.prepend($('<div class="level"></div>').append(level_of_friends));
      setTimeout(function() { sort_each_level_of_friends_6(scores); }, 10);
    } else {
      div1.append('<br style="clear: both;"/>');
      display_result_7();
    }
  }

  function get_sorted_scores_5() {
    var scores = [];
    $.each(config.friend_pages, function(i, friends) {
      $.each(friends, function(j, friend) {
        scores.push(friend.score);
      });
    });
    console_log(scores);
    scores = scores.numsort(1);
    console_log(scores);
    sort_each_level_of_friends_6(scores);
  }
  
  function score_each_page_of_friends_3(page, index_in_page) {
    var page_of_friends = config.friend_pages[page];
    if (page_of_friends) {
      var friend = page_of_friends[index_in_page];
      if (friend) {
        if (friend.bigurl_wait && friend.bigurl_wait > 0 && page_of_friends[index_in_page+1]) {
          console_log("postpone", friend.screen_name, friend.bigurl_wait);
          page_of_friends[index_in_page] = page_of_friends[index_in_page+1];
          page_of_friends[index_in_page+1] = friend;
          friend.bigurl_wait--;
          setTimeout(function() { score_each_page_of_friends_3(page, index_in_page); }, 500);
        } else {
          if (friend.link_htmls.length == 0) {
            friend.score = 0;
          } else {
            div3.html(friend.link_htmls.join(''));
            var number_of_visited_links = 0;
            $('#div3 a').each(function(i,href) {
              var jhref = $(href);
              if (jhref.css('color') == config.visited_color) {
                number_of_visited_links++;
                jhref.addClass('yes');
              } else {
                jhref.addClass('no');
              }
              href.title = '';
              href.href = '#';
            });
            friend.score = (number_of_visited_links * 10) - (friend.link_htmls.length - number_of_visited_links);
            console_log([friend.score, number_of_visited_links, friend.link_htmls.length]);
            var userdiv = $(userdivhtml.supplant(friend)).append(div3.html());
            div1.prepend(userdiv);
          }
          div3.html("");
          setTimeout(function() { score_each_page_of_friends_3(page, index_in_page + 1); }, 0);

          if (index_in_page < 30 && (index_in_page % 5) == 0) { say_guesstimate(page, index_in_page); } else if ((index_in_page % 30) == 0) { say_guesstimate(page, index_in_page); }
        }
      } else {
        setTimeout(function() { score_each_page_of_friends_3(page + 1, 0); }, 0);
      }
    } else {
      get_sorted_scores_5();
    }
  }

  function get_bigurls_for_friend_2(friend) {
    friend.bigurl_wait = 0;
    for (url in friend.unique_urls) {
      if (url.match(/\/\/(tinyurl\.com|bit\.ly|ff\.im|is\.gd|twurl\.nl|snipurl\.com|poprl\.com|tr\.im|cli\.gs|short\.ie)\//)) {
        friend.bigurl_wait++;
        console_log("match", friend.screen_name, friend.bigurl_wait);
        last_url = url;
        $.getJSON(config.big_url.supplant({query: url}), function(json) {
          if (url != json.tinyurl) friend.link_htmls.push("<a href='" + json.tinyurl + "' title='" + json.tinyurl + "'>" + '&hearts;' + "</a>");
          friend.bigurl_wait--;
          console_log("found", friend.screen_name, friend.bigurl_wait);
        });
      }
    }
  }

  function get_tweet_urls_from_each_friend_2(index_in_page) {
    var friend = config.friend_pages[config.page-1][index_in_page];
    if (friend) {
      $.getJSON(config.tweet_url.supplant(friend), function(json) {
        console_log(config.tweet_url.supplant(friend), json);
        $.each(json.results, function(index, tweet) {
          var match = tweet.text.match(/\w+\:\/\/\S+/g);
          if (match) $.each(match, function(i, url) {
            if (! friend.unique_urls[url]) {
              friend.unique_urls[url] = true;
              friend.link_htmls.push("<a href='" + url + "' title='" + url + "'>" + '&hearts;' + "</a>");
            }
          });
        });
        // if this friend did tweet some urls get their tiny versions
        if (friend.link_htmls[0]) {
          get_bigurls_for_friend_2(friend);
          var img = document.getElementById('img_' + friend.id);
          if (img && img.parentNode) img.parentNode.removeChild(img);
        }
        // queue next fella
        setTimeout(function() { get_tweet_urls_from_each_friend_2(index_in_page+1); }, 0);
      });
      // progress indicator
      if (index_in_page < 30 && (index_in_page % 5) == 0) { say_guesstimate(config.friend_pages.length - 1, index_in_page); } else if ((index_in_page % 30) == 0) { say_guesstimate(config.friend_pages.length - 1, index_in_page); }
    } else if (index_in_page >= 99) {
      // not last page yet, proceed
      get_page_of_friends_and_process_1(config.screen_name, config.page + 1);
    } else {
      // last page reached
      score_each_page_of_friends_3(0, 0);
    }
  }

  window.config = {
    production: {
      big_url: "http://jsonp-bigurl.appspot.com/?callback=?&url={query}",
      friends_ids_url: "http://twitter.com/friends/ids.json?screen_name={screen_name}&callback=?",
      friends_url: "http://twitter.com/statuses/friends.json?screen_name={screen_name}&page={page}&callback=?",
      tweet_url: "http://search.twitter.com/search.json?q=from%3A{screen_name}+filter%3Alinks&callback=?"
    },
    development: {
      big_url: "http://jsonp-bigurl.appspot.com/?callback=?&url={query}",
      friends_ids_url: "/{screen_name}.friends.ids.json?callback=?",
      friends_url: "/{screen_name}.friends.{page}.json?callback=?",
      tweet_url: "/{screen_name}.tweets.json?callback=?"
    }
  }
  
  function get_page_of_friends_and_process_1(screen_name, page) {
    console_log("get_page_of_friends_and_process_1", page);
    config.screen_name = screen_name;
    config.page = page;
    $.getJSON(config.friends_url.supplant(config), function(friends) {
      config.friend_pages.push(friends);
      $.each(friends, function(index, friend) {
        // preprocessing
        friend.unique_urls = {};
        friend.link_htmls = [];
        var img = document.createElement('img');
        img.src = friend.profile_image_url;
        img.className = 'profile small';
        img.id = "img_" + friend.id;
        img.title = friend.screen_name;
        div2[0].appendChild(img);
      });
      get_tweet_urls_from_each_friend_2(0);
    });
  }

  function say_guesstimate(page, processed) {
    processed = (page * 100) + processed;
    if (processed) {
      config.took = ((new Date()).getTime() - config.start) / 1000.0;
      config.guess = (config.friends_count * (config.took / processed));
      config.remaining = ((config.guess - config.took) + "").replace(/(\.\d).+$/g, '');
      $('h1#answer').html('A: <em style="font-size: 0.6em;">' + processed + '/' + config.friends_count + ' friends so far. This will take another ' + config.remaining + ' seconds...</em></h1>');
    } else {
      config.guess = 10;
      $('h1#answer').html('A: <em style="font-size: 0.6em;">This will take a minute...</em></h1>');
    }
  }

  config = config[window.env];
  function main(event) {
    event.preventDefault();
    config.screen_name = $('#username').val();
    $('form').unbind().remove();
    $('h1').after('<h1 id="answer">A: </h1>');
    $.getJSON(config.friends_ids_url.supplant(config), function(friend_ids) {
      config.friends_count = friend_ids.length;
      config.friend_ids = friend_ids;
      config.start = new Date();
      config.friend_pages = [];
      say_guesstimate(0, 0);
      get_page_of_friends_and_process_1(config.screen_name, 1);
    });
    $('#disclaimer').remove();
  }

  if (visited_link.length == 0) {
    $('body').html("<h1>Sorry, your privacy settings are too restrictive :-(</h1>");
  } else {
    config.visited_color = visited_link.css('color');
    $('#div3 a').remove();
    $('#username_get').click(main);
    $('form').submit(main);
    $('#username').focus();
  }

  $('#disclaimer').css({
    top: ($(window).height() - $('#disclaimer').height() - 5) + 'px',
    left: '10px',
    position: 'absolute'
  });
});

