//
// Reddit Score Revealer
//
// Peteris Krumins (peter@catonmat.net), 2007.08.25
// http://www.catonmat.net  -  good coders code, great reuse
//
// --------------------------------------------------------------------
//
// This is a Greasemonkey user script.
//
// To install, you need Greasemonkey: http://greasemonkey.mozdev.org/
// Once you have it installed, reload this page and the FireFox will
// offer you to install it automatically.
//
// --------------------------------------------------------------------
//
// ==UserScript==
// @name          Reddit Score Revealer
// @namespace     http://www.catonmat.net
// @description   Reveals score of newly published posts
// @include       http://*.reddit.com/*
// @include       http://reddit.com/*
// ==/UserScript==
//
// =======================================================================

// Each subreddit has its own widget, we need to find which subreddit we're at.
var subreddit = find_subreddit(location.host);

// Find *all* entries, I wrote this function, might come handy if I develop
// something else cool for reddit :)
var entries = find_entries();

// Find just the newly posted entries (score not visible), and center align
// existing vote boxes (so it looked better)
var new_entries = [];
for (var i = 0; i < entries.length; i++) {
    if (!entries[i].score_visible) new_entries.push(entries[i]);
    else entries[i].vote_td.setAttribute('align', 'center');
}

display_votes(new_entries);

//
// display_votes
//
// Given a list of reddit entries, changes the <td> containing up/down vote
// with the widget
//
function display_votes(entries) {
    for (var i = 0; i < entries.length; i++) {
        entries[i].vote_td.innerHTML = generate_widget_html(entries[i]);
    }
}

//
// generate_widget_html
//
// Given an entry, generates HTML code for up/down voting widget
//
function generate_widget_html(entry) {
    var host = "reddit.com";
    if (subreddit.length) {
        host = subreddit + ".reddit.com";
    }
    var html = '<iframe src="http://' + host + '/button?t=2&url=';
    html += encodeURIComponent(entry.url);
    html += '&title=' + encodeURIComponent(entry.title);
    html += '" height="51" width="39" scrolling="no" frameborder="0" style="margin-left: -5px"></iframe>';

    return html;
}

//
// find_subreddit
//
// Given a host, returns subreddit's name.
// For example, given "programming.reddit.com" it returns "programming"
// Given just "reddit.com" it returns null
//
function find_subreddit(host) {
    var sub = host.match(/^\w+/);
    if (sub == "reddit")
        return '';

    return sub;
}

//
// find_entries
//
// Returns an array of objects representing all reddit entries
//
function find_entries() {
    // Each entry is represented by two <tr>s.
    // The first one contains entry number, up/down vote and title
    // The second contains info when it was posted, by whom, etc.
    //
    const TITLE_TR = 1;
    const DATE_TR  = 2;

    // Each entry is encompassed in <tr class="evenRow"> or <tr class="oddRow">
    //
    var trs = document.getElementsByTagName('tr'); // gets all <tr>s

    var entries = [];
    var entry = {};
    var tr_state = TITLE_TR; 
    for (var i = 0; i < trs.length; i++) {
        if (/(even|odd)Row/.test(trs[i].className)) {
            if (tr_state == TITLE_TR) {
                var info  = get_title_url_box(trs[i]);
                if (!info) break;

                for (var e in info)
                    entry[e] = info[e];

                tr_state = DATE_TR;
            }
            else {
                var time_info = get_time_info(trs[i]);
                if (!time_info) break;

                for (var e in time_info)
                    entry[e] = time_info[e];

                entries.push(entry);
                entry = {};

                tr_state = TITLE_TR;
            }
        }
    }

    return entries;
}

//
// get_title_url_box
//
// Gets title, url and vote box <td> element from the first <tr>
// representing a reddit entry.
//
function get_title_url_box(tr) {
    var tds = tr.getElementsByTagName('td');
    if (!tds) return;

    var a = first_elem_child(tds[2], 1 /* Node.ELEMENT_NODE */);
    if (!a) return;

    return {
        vote_td: tds[1],
        url:     a.href,
        title:   a.text.replace(/^\s+/, '')
    };
}

//
// get_time_info
//
// Gets time info for an entry
//
function get_time_info(tr) {
    var td = first_elem_child(tr, 1 /* Node.ELEMENT_NODE */);
    if (!td) return;

    var time_text = first_elem_child(td, 3 /* Node.TEXT_NODE */);
    if (!time_text) return;

    var time_ago = extract_time_info(time_text.textContent);
    if (time_ago) {
        return {
            time_ago:      time_ago,
            score_visible: false
        };
    }
    else {
        time_text = get_elem_child(td, 3 /* Node.TEXT_NODE */, 2);
        if (!time_text) return;

        time_ago = extract_time_info(time_text.textContent);
        if (time_ago) {
            return {
                time_ago:      time_ago,
                score_visible: true
            };
        }
        return;
    }
}

//
// extract_time_info
//
// Extracts how long ago the entry was posted
//
function extract_time_info(str) {
    var m = str.match(/posted (\d+ .+) ago/);
    if (m) return m[1];

    return;
}

//
// first_elem_child
//
// Returns first child of a node which is of a given type
//
function first_elem_child(node, type) {
    return get_elem_child(node, type, 1);
}

//
// get_elem_child
//
// Returns n-th child of a node which is of a given type
//
function get_elem_child(node, type, n) {
    var child = node.firstChild;
    var i = 1;
    while (child) {
        if (child.nodeType == type && i++ == n) break;
        child = child.nextSibling;
    }

    return child;
}


