// ==UserScript==
// @name           4chan Spam Filter
// @namespace      http://www.toadking.com/greasemonkey#4chanSpamFilter
// @description    Easily hide spam posts
// @include        http://cgi.4chan.org/*
// @include        http://img.4chan.org/*
// @include        http://orz.4chan.org/*
// @include        http://zip.4chan.org/*
// ==/UserScript==

// lol version 2

// Like indexOf, except it treats strings in the array with certain formatting as regular expressions
// http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:indexOf#Compatibility
Array.prototype.match = function(efl)
{
	var from = Number(arguments[1]) || 0;
	var len = this.length;
	from = (from < 0) ? Math.ceil(from) : Math.floor(from);

	if (from < 0)
		from += len;

	for (; from < len; from++) {
		if (from in this && typeof this[from] != "undefined") {
			var rexp = this[from].match(/^\/(.*)\/([gim]*)$/);

			try {
				if (rexp) {
					var testExp = new RegExp(rexp[1], rexp[2]);

					if (testExp.exec(efl))
						return from;
				} else if (this[from] === efl)
					return from;
			} catch (e) {
				GM_log("WARNING! Couldn't run the \"" + this[from] + "\" filter! (Possible broken regular expression?)");
			}
		}
	}

	return -1;
};

var posts = 0;

function SpamFilter_StripShit(message)
{
	var fortunes = new RegExp("^Your fortune: (Average Luck|Bad luck|Better not tell you now|Excellent Luck|Godly Luck|Good Luck|Good news will come to you by mail|Outlook good|Reply hazy, try again|Very Bad Luck|You will meet a dark handsome stranger|\xEF\xBD\xB7\xEF\xBE\x80\xE2\x94\x81\xE2\x94\x81\xE2\x94\x81\xE2\x94\x81\xE2\x94\x81\xE2\x94\x81\\(\xF\xBE\x9F\xE2\x88\x80\xF\xBE\x9F\\)\xE2\x94\x81\xE2\x94\x81\xE2\x94\x81\xE2\x94\x81\xE2\x94\x81\xE2\x94\x81 !!!!)", "g");
	return message.replace(fortunes, "");
}

function SpamFilter_ShowSpam(e)
{
	e.preventDefault();

	e.target.nextSibling.style.removeProperty("display");
	e.target.parentNode.removeChild(e.target.previousSibling);
	e.target.parentNode.removeChild(e.target);

	return false;
}

function SpamFilter_DoHide(currentReply)
{
	currentReply.style.setProperty("display", "none", "important");
	/*var redLine = document.createElement("hr");
	redLine.color = "red";
	redLine.noShade = true;
	redLine.width = "40%";
	redLine.align = "left";
	currentReply.parentNode.insertBefore(redLine, currentReply);
	var unhidePost = document.createElement("a");
	unhidePost.href = "#unhideme";
	unhidePost.className = "quotejs";
	unhidePost.title = "Show this post";
	unhidePost.appendChild(document.createTextNode("[Show]"));
	unhidePost.addEventListener("click", SpamFilter_ShowSpam, false);
	currentReply.parentNode.insertBefore(unhidePost, currentReply);*/
}

function SpamFilter_HidePost(e)
{
	e.preventDefault();

	var currentReply = e.target;

	while (currentReply.nodeName.toUpperCase() != "TABLE")
		currentReply = currentReply.parentNode;

	SpamFilter_DoHide(currentReply);
}

function SpamFilter_AddToList(e)
{
	e.preventDefault();

	try {
		var spamList = eval(GM_getValue("SpamFilter_Spam"));
	} catch (e) {
		var spamList = new Array();
	}

	if (typeof spamList != "object")
		spamList = new Array();

	var message = SpamFilter_StripShit(e.target.parentNode.getElementsByTagName("blockquote")[0].textContent);
	spamList.push(message);
	GM_setValue("SpamFilter_Spam", spamList.toSource());
	posts = 0;
	SpamFilter_PopulateList();

	return false;
}

function SpamFilter_HideSpam()
{
	try {
		var spam = eval(GM_getValue("SpamFilter_Spam"));
	} catch (e) {
		var spam = new Array();
	}

	if (typeof spam != "object")
		spam = new Array();

	var replys = document.evaluate("//blockquote/ancestor::table", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);

	// Hack for compatability with the 4chan extension's inline thread expansion
	if (posts == replys.snapshotLength)
		return;

	posts = replys.snapshotLength;

	for (var i = 0; i < posts; i++) {
		var currentReply = replys.snapshotItem(i);
		var message = SpamFilter_StripShit(currentReply.getElementsByTagName("blockquote")[0].textContent);

		if (spam.match(message) != -1 && (!currentReply.previousSibling || (currentReply.previousSibling.nodeName.toUpperCase() != "A" || currentReply.previousSibling.href == "")))
			SpamFilter_DoHide(currentReply);

		var postHeader = currentReply.getElementsByTagName("br");

		if (postHeader.length == 0 || postHeader[0].parentNode.nodeName.toUpperCase() == "BLOCKQUOTE")
			postHeader = currentReply.getElementsByTagName("blockquote")[0];
		else
			postHeader = postHeader[0];

		if (postHeader.previousSibling.nodeName.toUpperCase() == "A")
			continue;

		var hideAllPosts = document.createElement("a");
		hideAllPosts.href = "#hidemeall";
		hideAllPosts.className = "quotejs";
		hideAllPosts.title = "Hide ALL posts like this from now on";
		hideAllPosts.addEventListener("click", SpamFilter_AddToList, false);
		hideAllPosts.appendChild(document.createTextNode("[All]"));
		postHeader.parentNode.insertBefore(document.createTextNode(" "), postHeader);
		postHeader.parentNode.insertBefore(hideAllPosts, postHeader);
		var hidePost = document.createElement("a");

		hidePost.href = "#hideme";
		hidePost.className = "quotejs";
		hidePost.title = "Hide this post";
		hidePost.addEventListener("click", SpamFilter_HidePost, false);
		hidePost.appendChild(document.createTextNode("[Hide]"));
		postHeader.parentNode.insertBefore(document.createTextNode(" "), postHeader);
		postHeader.parentNode.insertBefore(hidePost, postHeader);
	}
}

function SpamFilter_SaveList(e)
{
	e.preventDefault();

	var items = document.evaluate('//div[@id="SpamFilter_List"]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.getElementsByTagName("textarea");

	var spamList = new Array();

	for (var i = 0; i < items.length; i++) {
		spamList.push(items[i].value);
	}

	GM_setValue("SpamFilter_Spam", spamList.toSource());

	return false;
}

function SpamFilter_HideList(e)
{
	e.preventDefault();

	try {
		var list = document.evaluate('//div[@id="SpamFilter_List"]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
		list.parentNode.removeChild(list);
	} catch (e) {}

	return false;
}

function SpamList_DeleteItem(e)
{
	e.preventDefault();

	var item = e.target.parentNode;

	item.parentNode.removeChild(item);

	return false;
}

function SpamFilter_PopulateList()
{
	var list = document.evaluate('//div[@id="SpamFilter_List"]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);

	try {
		if (!list || !list.singleNodeValue)
			return;
		else
			list = list.singleNodeValue;
	} catch (e) {
		return;
	}

	while (list.childNodes.length != 2)
		list.removeChild(list.lastChild);

	
	try {
		var spamList = eval(GM_getValue("SpamFilter_Spam"));
	} catch (e) {
		var spamList = new Array();
	}

	if (typeof spamList != "object")
		spamList = new Array();

	spamList.forEach(function(element, index, array)
	{
		var itemDiv = document.createElement("div");
		itemDiv.style.setProperty("clear", "both", "important");
		itemDiv.style.setProperty("width", "100%", "important");
		itemDiv.style.setProperty("padding-top", "20px", "important");

		var itemText = document.createElement("textarea");
		itemText.rows = 6;
		itemText.style.setProperty("width", "80%", null);
		itemText.value = element;
		itemDiv.appendChild(itemText);

		var delItem = document.createElement("a");
		delItem.href = "#delete";
		delItem.title = "Delete this filter";
		delItem.addEventListener("click", SpamList_DeleteItem, false);
		delItem.appendChild(document.createTextNode("[Del]"));
		itemDiv.appendChild(delItem);

		list.appendChild(itemDiv);
	});
}

function SpamFilter_ShowList(e)
{
	e.preventDefault();

	var spamListDiv = document.createElement("div");
	spamListDiv.id = "SpamFilter_List";
	spamListDiv.className = "reply"
	spamListDiv.style.setProperty("padding", "1px", "important");
	spamListDiv.style.setProperty("border", "black 1px solid", "important");
	spamListDiv.style.setProperty("position", "fixed", "important");
	spamListDiv.style.setProperty("top", "1px", "important");
	spamListDiv.style.setProperty("left", "1px", "important");
	spamListDiv.style.setProperty("z-index", "2", "important");
	spamListDiv.style.setProperty("width", "50%", "important");
	spamListDiv.style.setProperty("max-height", "50%", "important");
	spamListDiv.style.setProperty("overflow", "auto", "important");

	var saveSpamList = document.createElement("a");
	saveSpamList.href = "#save";
	saveSpamList.title = "Save this list";
	saveSpamList.style.setProperty("display", "block", "important");
	saveSpamList.style.setProperty("float", "left", "important");
	saveSpamList.addEventListener("click", SpamFilter_SaveList, false);
	saveSpamList.appendChild(document.createTextNode("Save"));
	spamListDiv.appendChild(saveSpamList);

	var closeSpamList = document.createElement("a");
	closeSpamList.href = "#close";
	closeSpamList.title = "Close this list";
	closeSpamList.style.setProperty("display", "block", "important");
	closeSpamList.style.setProperty("float", "right", "important");
	closeSpamList.addEventListener("click", SpamFilter_HideList, false);
	closeSpamList.appendChild(document.createTextNode("X"));
	spamListDiv.appendChild(closeSpamList);

	document.body.appendChild(spamListDiv);

	SpamFilter_PopulateList();

	return false;
}

function SpamFilter_CreateMenu()
{
	var openLink = document.createElement("a");
	openLink.href = "#open";
	openLink.title = "Open up the 4chan Spam Filter list";
	openLink.className = "reply"
	openLink.style.setProperty("display", "block", "important");
	openLink.style.setProperty("padding", "1px", "important");
	openLink.style.setProperty("border", "black 1px solid", "important");
	openLink.style.setProperty("position", "fixed", "important");
	openLink.style.setProperty("top", "17px", "important");
	openLink.style.setProperty("left", "1px", "important");
	openLink.style.setProperty("z-index", "1", "important");
	openLink.addEventListener("click", SpamFilter_ShowList, false);
	openLink.appendChild(document.createTextNode("Spam"));
	document.body.appendChild(openLink);
	document.addEventListener("DOMNodeInserted", SpamFilter_HideSpam, false);
}

setTimeout(SpamFilter_CreateMenu, 20);
setTimeout(SpamFilter_HideSpam, 20);