/* If you're reading this, you might as well skip this and just use the Digg JSONP Api :) */
/*********** CONSTANTS ***********/
var COMMENTS_PER_REQUEST = 100;
var STORIES_PER_REQUEST = 100;
var MAX_COMMENTS = 10000;
/*********************************/

var params = {};
var digg = {
	"username":		"",
	"totalComments":	-1,
	"commentsParsed":	0,
	"comments":		[],
	"stories":		[],
	"unrequestedStories":	[],
	"currentSort":		"",
	"minTime":		0,
	"maxTime":		0,
	"maxComments":		0,
	"commentsPerRequest":	0
};

var stats = [
	{"id": "up",		"hasGraph": true,	"graphColor": 6,	"graphVisible": false},
	{"id": "down",		"hasGraph": true,	"graphColor": 7,	"graphVisible": false},
	{"id": "rating",	"hasGraph": true,	"graphColor": 8,	"graphVisible": true},
	{"id": "replies",	"hasGraph": true,	"graphColor": 9,	"graphVisible": true},
	{"id": "range"	,	"hasGraph": false,	"graphColor": 5,	"graphVisible": false}
];

var GRAPH_COUNT = (function(){var cnt=0;for(var i=0;i<stats.length;i++){if(stats[i].hasGraph)cnt++;}return cnt;}).call();

var commentColumns = [
	{"id":	'story',	"commentAddCb": commentAddCbStory,	"sortCb": sortCbStory	},
	{"id":	'date',		"commentAddCb": commentAddCbDate,	"sortCb": sortCbDate	},
	{"id":	'up',		"commentAddCb": commentAddCbUp,		"sortCb": sortCbUp	},
	{"id":	'down',		"commentAddCb": commentAddCbDown,	"sortCb": sortCbDown	},
	{"id":	'rating',	"commentAddCb": commentAddCbRating,	"sortCb": sortCbRating	},
	{"id":	'range',	"commentAddCb": commentAddCbRange,	"sortCb": sortCbRange	},
	{"id":	'replies',	"commentAddCb": commentAddCbReplies,	"sortCb": sortCbReplies	},
	{"id":	'comment',	"commentAddCb": commentAddCbComment,	"sortCb": sortCbComment	}
];

function Story(id)
{
	this.id = id + "";
	this.comments = new Array();
	this.data = null;
}
Story.prototype.setData = function(data) { this.data = data; }
Story.prototype.addComment = function(comment) { this.comments.push(comment); }
Story.prototype.updateCommentLabels = function()
{
	for (var i = 0; i < this.comments.length; i++)
	{
		this.updateCommentLabel(this.comments[i]);
	}
}

Story.prototype.updateCommentLabel = function(comment)
{
	comment.eStoryLabel.innerHTML = 
		'<a href="' + this.data.href + 
		"?t=" + (comment.replyto ? comment.replyto : comment.id) +
		'#c' + comment.id + '">' + this.data.title + '</a>';
}

function Params(loc, dirs)
{
    var index = -1;
    var data = new String(loc);
    data = data.replace(/[\?&=]/g, "/");
    for (var i = 0; i < dirs.length; i++)
    {
        if ((index = data.indexOf("/" + dirs[i] + "/")) > 0)
        {
            data = data.substring(index + dirs[i].length + 2);
            break;
        }
    }
    var keys = data.split("/");
    for (var i = 0; i < keys.length - 1; i+=2)
        this[neaveruUnescape(keys[i])] = neaveruUnescape(keys[i+1]);
}
/*********** Comment Row Cell Creation Callbacks ***********/
function commentAddCbStory(comment) { return (comment.eStoryLabel = createTextElem("td", "Loading...")); }
function commentAddCbDate(comment) {
	var dt = new Date(comment.date * 1000);
	return createTextElem("td", (dt.getMonth() + 1) + '/' + dt.getDate() + '/' + dt.getFullYear() + ' ' + pad(dt.getHours()) + ':' + pad(dt.getMinutes()));
}
function commentAddCbUp(comment) { return createStatElem("td", comment.up); }
function commentAddCbDown(comment) { return createStatElem("td", -comment.down); }
function commentAddCbRating(comment) { return createStatElem("td", comment.rating); }
function commentAddCbRange(comment) { return createStatElem("td", comment.range); }
function commentAddCbReplies(comment) { return createStatElem("td", comment.replies); }
function commentAddCbComment(comment) { return createTextElem("td", '<a name="c' + comment.id + '"></a><div class="commentText">' + comment.content.replace(/\n/g, "<BR/>") + "</div>"); }
/***********************************************************/

/*********** Sorting Callbacks ***********/
function sortCbStory(a, b) 
{
	return string_compare(a.story && a.story.data ? a.story.data.title.toLowerCase() : "", b.story && b.story.data ? b.story.data.title.toLowerCase() : "");
}
function sortCbDate(a, b) { return integer_compare(parseInt(a.date), parseInt(b.date)); }
function sortCbUp(a, b) { return integer_compare(parseInt(a.up), parseInt(b.up)); }
function sortCbDown(a, b) { return -integer_compare(parseInt(a.down), parseInt(b.down)); }
function sortCbRating(a, b) { return integer_compare(parseInt(a.rating), parseInt(b.rating)); }
function sortCbRange(a, b) { return integer_compare(parseInt(a.range), parseInt(b.range)); }
function sortCbReplies(a, b) { return integer_compare(parseInt(a.replies), parseInt(b.replies)); }
function sortCbComment(a, b) { return string_compare(a.content.toLowerCase(), b.content.toLowerCase()); }
/*****************************************/

/*********** Status Row Callbacks ***********/
function statCallbackGetMax(stat, data) { return createStatElem("td", stat.maxComment[stat.id], '#c' + stat.maxComment.id); }
function statCallbackGetMin(stat, data) { return createStatElem("td", stat.minComment[stat.id], '#c' + stat.minComment.id); }
function statCallbackGetAverage(stat, data) { return createStatElem("td", stat.total / data); }
function statCallbackGetMedian(stat, data) { return createStatElem("td", getMedian(stat.id)); }
function statCallbackGetRange(stat, data) { return createStatElem("td", Math.abs(stat.maxComment[stat.id] - stat.minComment[stat.id])); }
function statCallbackGetTotal(stat, data) { return createStatElem("td", stat.total); }
/********************************************/

function initializeCommentsTable()
{
	var tbl, tr;
	tbl = $("tblComments");
	tbl.appendChild(tr = document.createElement("tr"));
	for (var i = 0; i < commentColumns.length; i++)
	{
		var commentColumn = commentColumns[i];
		tr.appendChild(createTextElem("th", commentColumn.id, 'javascript:sortComments(' + i + ');'));
	}
}

function initializeGraphs()
{
	var tbl, tr, th;
	var tbl = $("tblGraphs");
	var trLbls;

	tbl.appendChild(tr = document.createElement("tr"));
	tr.appendChild(th = createTextElem("th", "GRAPHS"));
	th.colSpan = GRAPH_COUNT;

	tbl.appendChild(trLbls = document.createElement("tr"));

	tbl.appendChild(tr = document.createElement("tr"));
	tr.style.textAlign = "center";

	for (var i = 0; i < stats.length; i++)
	{
		var graph = stats[i];
		if (!graph.hasGraph)
			continue;

		trLbls.appendChild(createTextElem("th", graph.id));

		var chk = document.createElement("input");
		var td = document.createElement("td");
		chk.type = "checkbox";
		chk.onclick = new Function("toggleCanvas(stats[" + i + "])");
		graph.graphCheck = chk;
		chk.checked = chk.defaultChecked = graph.graphVisible; //dear ie, i hate you, love neaveru
		td.appendChild(chk);
		tr.appendChild(td);

		graph.canvas = createCanvas();

		chk.onclick();
	}
	$("tblGraphs").appendChild(tr);
}

function sortHandler(sortCb, reverse) {
	return function(a, b) { 
		var rv = sortCb(a, b);
		if (!rv)
			rv = sortCbDate(a, b);
		return (reverse ? -rv : rv); 
	}
}

function sortComments(colNum)
{
	var column = commentColumns[colNum];
	var reverseSort = column.id == digg.currentSort;
	digg.currentSort = (reverseSort ? "" : column.id);
	for (var i = 0; i < digg.comments.length; i++)
		if (digg.comments[i].eRow)
			$("tblComments").removeChild(digg.comments[i].eRow);
	digg.comments = digg.comments.sort(sortHandler(column.sortCb, reverseSort));
	for (var i = 0; i < digg.comments.length; i++)
		$("tblComments").appendChild(digg.comments[i].eRow);
}


function sendDiggStoriesRequest()
{
	var count = 0;
	var stories = new Array();
	for (var id in digg.unrequestedStories)
	{
		stories.push(id);
		count++;
		if (count >= STORIES_PER_REQUEST)
			break;
	}

	if (stories.length)
	{
		var story = digg.unrequestedStories[stories[0]];
		for (var i = 0; i < stories.length; i++)
			delete digg.unrequestedStories[stories[i]];
		stories = stories.join(",");
		sendDiggRequest("stories/" + stories, "receiveDiggStoriesData", {count: STORIES_PER_REQUEST});
	}
}

function initializeStoryRequest()
{
	for (var key in digg.stories)
		digg.unrequestedStories[key] = digg.stories[key];
	if (digg.unrequestedStories.length > 0)
		sendDiggStoriesRequest();
}

function receiveDiggStoriesData(data)
{
	if (data.code)
	{
		setStatus("Digg returned an error: " + data.message, true);
		return;
	}
	handleStories(data.stories);
	sendDiggStoriesRequest();
}

function handleStories(diggStories)
{
	var nDiggStories = diggStories.length;
	for (var i = 0; i < nDiggStories; i++)
	{
		var story = getOrCreateStory(diggStories[i].id);
		story.data = diggStories[i];
		story.updateCommentLabels();
	}
}
function receiveDiggCommentsData(data)
{
	if (data.code)
	{
		setStatus("Digg returned an error: " + data.message);
		return;
	}
	digg.totalComments = parseInt(data.total);
	if (data.comments)
		handleComments(data.comments);
	setPercentDone(digg.commentsParsed, digg.totalComments > digg.maxComments ? digg.maxComments : digg.totalComments);

	if (digg.commentsParsed < digg.totalComments && digg.commentsParsed < digg.maxComments)
		sendDiggCommentsRequest();
	else 
		parseDiggComments();
}
function getOrCreateStory(id)
{
	if (digg.stories[id])
		return digg.stories[id];
	var story = new Story(id);
	digg.stories[story.id] = story;
	return story;
}
function handleComments(comments)
{
	var nComments = comments.length;
	for (var i = 0; i < nComments; i++)
	{
		var comment = comments[i];
		comment.story = getOrCreateStory(comment.story);
		comment.story.addComment(comment);
		if (comment.story.data)
			comment.story.addCommentLabel(comment);
	}
	digg.comments = digg.comments.concat(comments);
	digg.commentsParsed += nComments;
}


function parseDiggComments(comments)
{
	var totalUp = 0, totalDown = 0, totalReplies = 0;
	//var maxUp = 0, maxDown = 0, maxRating = 0, maxReplies = 0;
	//var minUp = 10000, minDown = 10000, minRating = 10000, minReplies = 10000;
	var maxUp = null, maxDown = null, maxRating = null, maxReplies = null;
	var minUp = null, minDown = null, minRating = null, minReplies = null;
	var totalComments = digg.comments.length;
	if (totalComments == 0)
	{
		setStatus("0 comments found");
		return;
	}
	setStatus("Computing data...");
	digg.comments = digg.comments.reverse();
	initializeGraphs();
	initializeCommentsTable();

	var comment = digg.comments[0];
	var absMin; var absMax;
	for (var i = 0; i < stats.length; i++)
	{
		absMin = absMax = comment.up;
		stats[i].maxComment = comment;
		stats[i].minComment = comment;
		stats[i].total = 0;
	}
	for (var i = 0; i < totalComments; i++)
	{
		comment = digg.comments[i];
		comment.rating = parseInt(comment.up) - parseInt(comment.down);
		comment.range = parseInt(comment.up) + parseInt(comment.down);
		for (var j = 0; j < stats.length; j++)
		{
			var stat = stats[j];
			var id = stat.id;
			if (parseInt(comment[id]) > stat.maxComment[id])
				stat.maxComment = comment;
			if (parseInt(comment[id]) < stat.minComment[id])
				stat.minComment = comment;
			stat.total += parseInt(comment[id]);
		}

	}
	createStatsTable(stats, digg.comments);

	for (var i = 0; i < stats.length; i++)
	{
		var id = stats[i].id;
		if (stats[i].hasGraph)
		{
			if (absMax < parseInt(stats[i].maxComment[id]))
				absMax = parseInt(stats[i].maxComment[id]);
			if (absMin > parseInt(stats[i].minComment[id]))
				absMin = parseInt(stats[i].minComment[id]);
		}
	}

	drawGrid(digg.comments, absMin, absMax);
	for (i = 0; i < stats.length; i++)
	{
		if (!stats[i].hasGraph)
			continue;
		stats[i].graphMin = absMin;
		stats[i].graphMax = absMax;
		if (stats[i].graphCheck.checked)
			stats[i].graphCheck.onclick();
	}
	$("divLoading").style.display = "none";
	$("divMain").style.display = "";

	addCommentRows(digg.comments);
	initializeStoryRequest();
}
function createStatsTable(stats, comments)
{
	var tbl, tr, th;
	tbl = $("tblStats");
	tbl.appendChild(tr = document.createElement("tr"));

	tr.appendChild(th = document.createElement("th"));
	th.rowSpan = 2;

	tr.appendChild(th = createTextElem("th", "stats"));
	th.colSpan = stats.length;

	tbl.appendChild(tr = document.createElement("tr"));
	for (var i = 0; i < stats.length; i++)
		tr.appendChild(createTextElem("th", stats[i].id));

	addStatsRowByCallback("Max", stats, statCallbackGetMax);
	addStatsRowByCallback("Min", stats, statCallbackGetMin);
	addStatsRowByCallback("Average", stats, statCallbackGetAverage, comments.length);
	addStatsRowByCallback("Median", stats, statCallbackGetMedian);
	addStatsRowByCallback("Range", stats, statCallbackGetRange);
	addStatsRowByCallback("Total", stats, statCallbackGetTotal);
}

function addCommentRows(comments)
{
	for (var i = comments.length - 1; i >= 0; i--)
		addCommentRow(comments[i]);
}

function hasError(data)
{
	return (data.code ? true : false);
}
function receiveDiggStoryData(data)
{
	for (i=0;i<data.stories.length;i++)
		parseStory(data.stories[i]);
}
function parseStory(story)
{
	digg.stories[story.id].data = story;
	var title = story.title;
	var link = story.href;
	var popular = (story.status == "popular");
	for (var i=0;i<digg.stories[story.id].comments.length;i++)
	{
		var commentRow = $('rowComment' + digg.stories[story.id].comments[i]);
		if (commentRow)
			alert("Yeah");
	}
}
function setPercentDone(current, total)
{
	var value = (total ? Math.round(current/total*100) : "100");
	$("spnPercentDone").innerHTML = value + '% (' + current + ' of ' + total + ')';
}
function setStatus(txt, fatal)
{
	$("divStatus").innerHTML = txt;
	if (fatal)
	{
		$('imgLoading').style.display = 'none';
	}
}
function newStory()
{
	return {"comments": []};
}

function addCommentRow(comment)
{
	var tr = document.createElement("tr");
	for (var i = 0; i < commentColumns.length; i++)
		tr.appendChild(commentColumns[i].commentAddCb(comment));
	$('tblComments').appendChild(tr);
	comment.eRow = tr;
}

function getMedian(which)
{
	var sArr = new Array();
	for (var i=0;i<digg.comments.length;i++)
		sArr.push(parseInt(digg.comments[i][which]));
	sArr.sort(integer_compare);

	if (sArr.length % 2)
		return sArr[parseInt(sArr.length / 2)];
	else
		return (sArr[sArr.length / 2] + sArr[sArr.length / 2 + 1])/2;
}
function addStatsRowByCallback(lbl, stats, cb, data)
{
	var tr = document.createElement("tr");
	tr.appendChild(createTextElem("th", lbl));
	for (var i = 0; i < stats.length; i++)
	{
		tr.appendChild(cb(stats[i], data));
	}
	$("tblStats").appendChild(tr);
}
function createLink(txt, link)
{
	return '<a href="' + link + '">' + txt + '</a>';
}
function createTextElem(elemType, value, link)
{
	var elem = document.createElement(elemType);
	elem.innerHTML = link ? createLink(value, link) : value;
	return elem;
}
function createStatText(value, link)
{
	var txt = Math.round(value * 100) / 100;
	return link ? createLink(txt, link) : txt;
}
function createStatElem(elemType, value, link)
{
	var elem = createTextElem(elemType, createStatText(value, link));
	elem.className = (value < 0 ? "negStat" : "stat");
	return elem;
}
function setStatValue(elemId, value)
{
	$(elemId).innerHTML = Math.round(value*100)/100;
}
function $(id)
{
	return document.getElementById(id);
}
function sendDiggRequest(id, callback, params)
{
	var request = "http://services.digg.com/" + id + "?appkey=http%3A%2F%2Fwww.neaveru.com&type=javascript&callback=" + callback;
	if (params)
		for (var key in params)
			request += '&' + key + '=' + params[key];
	var scr = document.createElement("script");
	scr.type = "text/javascript";
	scr.charset = "utf-8";
	scr.src = request;
	document.getElementsByTagName("head")[0].appendChild(scr);
}
function sendDiggCommentsRequest()
{
	sendDiggRequest("user/" + digg.username + "/comments", "receiveDiggCommentsData",
		{"count": digg.commentsPerRequest, "offset": digg.commentsParsed, "min_date": digg.minTime});
}
function drawGrid(comments, min, max)
{
	var g = new line_graph();
	g.labelsOnly = true;
	setGraphWidth(g, digg.comments.length);
	for (var i = 0; i < comments.length; i++)
	{
		var lbl = "";
		if (i % 4 == 0)
		{
			var dt = new Date(comments[i].date * 1000);
			lbl = (pad(dt.getMonth()+1) + '/' + pad(dt.getDate()) + '/' + pad(dt.getYear() % 100)).split("").join("<BR/>");
		}
		g.add(lbl, 0);
	}
	g.setMin(min);
	g.setMax(max);

	var grid = createCanvas();
	g.render(grid, "", 550);
	grid.style.width = g.width;

}
function createCanvas()
{
	var grid = document.createElement("div");
	grid.className = "canvas";
	var subGrid = document.createElement("div");
	subGrid.className = "subcanvas";
	grid.appendChild(subGrid);
	$('divCanvases').appendChild(grid);
	return subGrid;
}
function setGraphWidth(g, commentCount)
{
	g.dw = (commentCount < 50 ? 15 : 5);
}
function plotPoints(eWhere, iColor, sKey, min, max, gridOnly)
{
	var g = new line_graph();
	g.skipGrid = true;
	setGraphWidth(g, digg.comments.length);
	for (var i = 0; i < digg.comments.length; i++)
	{
		var lbl = "";
		g.add(lbl, gridOnly ? 0 : digg.comments[i][sKey]);
	}
	g.setColor(iColor);
	g.setMin(min);
	g.setMax(max);
	g.render(eWhere, "", 550);
	eWhere.style.width = g.width;
}
function toggleCanvas(graph)
{
	if (!graph.drawn && digg.comments.length && graph.graphCheck.checked && graph.graphMin != undefined && graph.graphMax != undefined)
	{
		digg.comments.sort(sortCbDate);
		graph.drawn = 1;
		plotPoints(graph.canvas, graph.graphColor, graph.id, graph.graphMin, graph.graphMax);
	}
	graph.canvas.style.display = (graph.graphCheck.checked ? "" : "none");
}
function submitUser(name)
{
	name = name.replace(/^\s+|\s+$/g, "");
	if (!name)
	{
		alert("Please type in a valid user");
		return;
	}
	//no need to worry about hacking... its js afterall
	digg.username = name;
	$("divGetUser").style.display = "none";
	$("divLoading").style.display = "";
	sendDiggCommentsRequest();
}
function neaveruUnescape(txt)
{
	return txt ? unescape(txt.replace('+', ' ')) : "";
}
function getParamInt(key, defaultValue)
{
	if (params[key] == null)
		return defaultValue;
	var value = parseInt(params[key]);
	return (isNaN(value) || value <= 0 ? defaultValue : value);
}
function handleStatsRequest(name)
{
	var days;
	digg.username = name;

	digg.maxComments = getParamInt("max_comments", MAX_COMMENTS);
	//digg.maxTime = getParamInt("max_time", 0);
	digg.commentsPerRequest = (digg.maxComments < COMMENTS_PER_REQUEST ? digg.maxComments : COMMENTS_PER_REQUEST);

	days = getParamInt("days", 0);
	if (days)
	{
		var today = new Date();
		today.setHours(0, 0, 0, 0);
		digg.minTime = parseInt((today - (24 * 60 * 60 * 1000 * days)) / 1000);
		if (digg.minTime < 0) digg.minTime = 0;
	}
	var tmpName = name;
	tmpName = tmpName.replace("<", "&lt;");
	tmpName = tmpName.replace(">", "&gt;");
	$("description").innerHTML = "Showing statistics" + 
		(digg.maxComments > 0 ? " on the last " + digg.maxComments + " comments" : "") +
		" for digg user " + tmpName + 
		(days > 0 ? ", in the last " + days + " days" : "");
	sendDiggCommentsRequest();
}
function pageLoad()
{
	params = new Params(window.location, ["digg", "stats.html"]);
	var name = params['stats'];
	//if (name && (name = name.replace(/^\s+|\s+$/g, "")) != "" && /^[\w@]+$/.test(name))
	if (name && (name = name.replace(/^\s+|\s+$/g, "")) != "")
	{
		handleStatsRequest(name);
	} else {
		setStatus("Invalid username", true);
	}
}


