BvS R00t Logger

Bvs R00t Logger 1.0.4

// ==UserScript==
// @name           BvS R00t Logger
// @namespace      rvR00t
// @description    Bvs R00t Logger 1.0.4
// @include        http*://*animecubed.com/billy/bvs/villagefields.html
// @include        http*://*animecubedgaming.com/billy/bvs/villagefields.html
// @version        1.0.6
// @history        1.0.6 New domain - animecubedgaming.com - Channel28
// @history        1.0.5 Now https compatible (Updated by Channel28)
// @history        1.0.4 (3/12/2011) Made FireFox 4 compatible.
// @history        1.0.3 fixed some extra data being saved in field responses that should have been removed, but were not because either I forgot to account from them or because people didn't follow the 'shortcoming rules'.
// @history        1.0.2 refixed the bug from 1.0.1 and changed the script name so old data won't be lost on updates.
// @history        1.0.1 Fixed field save when using Overture.
// ==/UserScript==

////////////////////////////////////////////
//// User Options
////////////////////////////////////////////

var showDialogResponse = true;

var enableHotkeys = false;

	//Note: If you enable hotkeys, only use numbers or uppercase letters for the hotkeys.
	//	It makes this easier and it can really only handle those correctly.

var hotkeyAction1 = '1';
var hotkeyAction2 = '2';
var hotkeyAction3 = '3';
var hotkeyAction4 = '4';
var hotkeyAction5 = '5';

////////////////////////////////////////////
////////////////////////////////////////////
////////////////////////////////////////////

var updateInProgress = false;
var pageSubmitted = false;

var lastR00tAction;
var GM_num;
var GM_names;
var GM_data;
var GM_addNewData;
var GM_newDataIndex;

var GMlink_num;
var GMlink_names;
var GMlink_data;
var GMlink_addNewData;
var GMlink_newDataIndex;

var key_1;
var key_2;
var key_3;
var key1;
var key2;
var key3;
var keyString;
var fieldText;
var fieldDifficulty;
var fieldActions = new Array();
var fieldResponse;

var dayrollTime = (5*60*60 + 15*60);//5:15
var d = new Date();
var currentTime = d.getTime();
var startTime = currentTime;
var localOffset = d.getTimezoneOffset() * 60000;
currentTime += localOffset; //UTC time in msec
currentTime += (3600000 * - 6);	//Billy time in msec
currentTime = Math.round(currentTime / 1000.0);

var fieldForm;

window.addEventListener("load", load, false);

if (enableHotkeys) {
	window.addEventListener("keyup", hotkey, false);
}

function hotkey(event) {
	//only works with letters, numbers, and very few other keys

	if (pageSubmitted)
		return;

//alert(String.fromCharCode(event.keyCode));

	var ch = String.fromCharCode(event.keyCode);
	var form = null;

	if (ch == hotkeyAction1) {
		form = document.forms.namedItem("search1");
	} else if (ch == hotkeyAction2) {
		form = document.forms.namedItem("search2");
	} else if (ch == hotkeyAction3) {
		form = document.forms.namedItem("search3");
	} else if (ch == hotkeyAction4) {
		form = document.forms.namedItem("search4");
	} else if (ch == hotkeyAction5) {
		form = document.forms.namedItem("search5");
	}

	if (form) {
		form.wrappedJSObject.submit();
		pageSubmitted = true;
	}
}

function load(e) {
	GM_addStyle("div#bvsR00tLogger {background-image: url('http://rveach.romhack.org/BvS/scrollbg2.JPG'); min-width: 100px; max-width: 200px; position: fixed; bottom: 8px; right: 8px; padding: 0; border: 1px solid black; text-align: center;}");
	GM_addStyle("#bvsR00tLogger h1 {color: white; font-size: 16px; font-weight: bold; padding: 4px; margin: 0; background-image: url('http://rveach.romhack.org/BvS/scrolldark.jpg');}");

	try {
		fieldForm  = document.getElementsByName("field");
		if (fieldForm.length) {
			////////////////////////////////////////////////
			// Init
			////////////////////////////////////////////////

			var snap;
			var match;
			var temp;
			var element;
			var i;
			var j;

			////////////////////////////////////////////////
			// Get Page Info
			////////////////////////////////////////////////

// FF 3: /html/body/center/table/tbody/tr/td/table/tbody/tr[2]/td/center/table/tbody/tr[3]/td[3]/center/table/tbody/tr/td/     center/table/tbody/tr/td/table
// FF 4: /html/body/center/table/tbody/tr/td/table/tbody/tr[2]/td/center/table/tbody/tr[3]/td[3]/center/table/tbody/tr/td/font/center/table/tbody/tr/td/table

			snap = document.evaluate("//center/table/tbody/tr/td/center/table/tbody/tr/td/table", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
			if ((snap == null) || (snap.snapshotLength == 0)) {
				snap = document.evaluate("//center/table/tbody/tr/td/font/center/table/tbody/tr/td/table", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
			}

			if ((snap != null) && (snap.snapshotLength > 0)) {
				temp = snap.snapshotItem(0).textContent.trim().replace(/(\n)|(\n+)/g, ",").split(",");

				if (temp.length > 3) {
					temp = temp.splice(-3);
				}

				keyString = temp.join(",");
			} else {
				alert("R00t Logger Error:\n\nFailed to find the Field Key!");
				return;
			}

//alert("KeyString: " + keyString);

			snap = document.evaluate("//center/table/tbody/tr/td/table/tbody/tr/td[1]/table[1]/tbody/tr/td", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
			if ((snap != null) && (snap.snapshotLength > 0)) {
				fieldText = snap.snapshotItem(0).textContent.trim();

				if (match = fieldText.match(/Difficulty Level:\s*(\d+)/)) {
					fieldDifficulty = match[1];
					fieldText = fieldText.replace(/Difficulty Level:\s*\d+/g, "").trim();
//alert("FieldDifficulty: " + fieldDifficulty);
				}
//alert("FieldText: " + fieldText);
			}

			i = 1;
			while ((temp = document.getElementsByName("search" + i)).length) {
				fieldActions.push(temp[0].textContent.removeHTML().trim());
				attachEventToForm(temp[0], newFormSubmit);

				i++;
			}

			if (fieldActions.length > 0) {
//alert("FieldActions: " + fieldActions);

				snap = document.evaluate("//center/table/tbody/tr/td/table/tbody/tr/td[2]/table[2]/tbody/tr/td", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
				if ((snap != null) && (snap.snapshotLength > 0)) {
					fieldResponse = snap.snapshotItem(0).textContent.trim();
					fieldResponse = fieldResponse.replace(/\n\s*Successes:\s*\d+\s*\n/m, "\n");
						//remove successes gotten
					fieldResponse = fieldResponse.replace(/\n\s*Success!\s*/m, "\n");
					fieldResponse = fieldResponse.replace(/\n\s*Failure!\s*/m, "\n");
						//remove successes/failure message

					fieldResponse = fieldResponse.replace(/\n\s*\+((([0-9]+,)+)?[0-9]+)\s*Bits!\s*/m, "");
					fieldResponse = fieldResponse.replace(/\n\s*\+((([0-9]+,)+)?[0-9]+)\s*Core!\s*/m, "");
					fieldResponse = fieldResponse.replace(/\n\s*\+((([0-9]+,)+)?[0-9]+)\s*Ryo!\s*/m, "");
					fieldResponse = fieldResponse.replace(/\n\s*\+((([0-9]+,)+)?[0-9]+)\s*Stamina!\s*(Total Bonus Event Stamina today:\s*((([0-9]+,)+)?[0-9]+)\s*\/\s*((([0-9]+,)+)?[0-9]+))?/m, "");
						//remove bit/core/ryo/stamina messages

					fieldResponse = fieldResponse.replace(/\s*The Guardian recedes into nothingness..\s*/m, "");
					fieldResponse = fieldResponse.replace(/\n\s*Field Key Found:\s*(\w+\-*\s*)+!\s*/m, "");
					fieldResponse = fieldResponse.replace(/\n\s*Item Found:\s*(\w+\-*\s*)+!\s*/m, "");
						//remove special messages

					fieldResponse = fieldResponse.replace(/\xA0/g, " ");
					fieldResponse = fieldResponse.replace(/ /g, " ");
					fieldResponse = fieldResponse.replace(/\n\n/g, "\n");
					fieldResponse = fieldResponse.trim();
						//remove &nbsp and \n\n

//alert("FieldResponse: " + fieldResponse);
				}
			}

			////////////////////////////////////////////////
			// Save Data
			////////////////////////////////////////////////
//encode:	"=%22, %=%25, |=%7C, \=%5C, &nbsp=%C0%A2

			lastR00tAction = GM_getValue("r00t_lastaction", "").trim();
			//lastR00tAction = getCookie("r00t_lastaction").trim();

			GM_num = 4;
			GM_names = new Array("savedFields", "savedFieldText", "savedFieldActions", "savedFieldResponses");
			GM_data = new Array();
			GM_addNewData = new Array(keyString, fieldText, fieldActions, fieldResponse);
			GM_newDataIndex = new Array();

			runGMAddData(0);

			GMlink_num = 4;
			GMlink_names = new Array("savedFieldLinkTextLinkDate", "savedFieldTextLinkActionLinkDiff",
						"savedFieldResponseLinkActionLinkTextLinkDiff",
						"savedCountLinkResponseLinkActionLinkTextLinkDiff");
			GMlink_data = new Array();
			GMlink_addNewData = new Array();
			GMlink_newDataIndex = new Array();

			GMlink_addNewData.push(
				new Array( 4, false, GM_newDataIndex[0], GM_newDataIndex[1], currentTime));
				//link field with field text with today's date

			if (GM_newDataIndex[2] != undefined) {
				GMlink_addNewData.push(
					new Array(-1, false, GM_newDataIndex[1], GM_newDataIndex[2].join(","), fieldDifficulty));
					//link field text with field actions with field difficulty

				if (lastR00tAction != "") {
					GMlink_addNewData.push(
						new Array(-1, false, GM_newDataIndex[3], GM_newDataIndex[2][fieldActions.indexOf(lastR00tAction)], GM_newDataIndex[1], fieldDifficulty));
						//link field response with field action used with field difficulty with field text
				} else {
					GMlink_addNewData.push(null);
				}
			} else {
				GMlink_addNewData.push(null);
				GMlink_addNewData.push(null);
			}

			runGMLinkAddData(0);

			if (lastR00tAction != "") {
				GMlink_addNewData.push(
					new Array(-1, true, GMlink_newDataIndex[2]));

				runGMLinkAddData(GMlink_names.length-1);
			}

			////////////////////////////////////////////////
			// Submit Updates
			////////////////////////////////////////////////

			var lastsave = GM_getValue("r00t_lastsave", "");

			if (lastsave == "")
				GM_setValue("r00t_lastsave", currentTime);
			else if (currentTime >= lastsave + 86400) {
				var query = "version=" + version;

				for (i = 0; i < GM_num; i++) {
					query += ("&" + GM_names[i] + "=");

					if ((GM_data[i] == null) || (GM_data[i] == undefined))
						query += GM_getValue("r00t_" + GM_names[i], "");
					else
						query += GM_data[i].join("|");
				}
				for (i = 0; i < GMlink_num; i++) {
					query += ("&" + GMlink_names[i] + "=");

					if ((GMlink_data[i] == null) || (GMlink_data[i] == undefined))
						query += GM_getValue("r00t_" + GMlink_names[i], "");
					else
						query += GMlink_data[i].join("|");
				}
//alert(query);
				QueryServer(query);
			}

			////////////////////////////////////////////////
			// Clean Up
			////////////////////////////////////////////////

			GM_setValue("r00t_lastaction", "");
			//setCookie("r00t_lastaction", "", 5);

			var endTime = d.getTime();

			if ((endTime - startTime) > 1)
				alert("Time to computer: " + (endTime - startTime) + " ms");

			if (fieldActions.length > 0) {
				//document.addEventListener('submit', newFormSubmit, true);

				/*unsafeWindow.HTMLFormElement.prototype.real_submit = unsafeWindow.HTMLFormElement.prototype.submit;
				unsafeWindow.HTMLFormElement.prototype.submit = newFormSubmit;*/

				/*elems = document.getElementsByTagName("form");

				for (i = 0; i < elems.length; i++) {
					elems[i].addEventListener('submit', newFormSubmit, true);
					elems[i].addEventListener('click', newFormSubmit, true);
				}*/
			}
		}
	}
	catch(e) {
		alert("Exception!\n\nError name: " + e.name + "\nError message: " + e.message);
	}
}

function newFormSubmit(e) {
	if ((e) && (e.preventDefault)) {
		e.preventDefault();
	}

	if (updateInProgress) {
		alert("R00t Logger:\n\nPlease wait on playing, an AJAX update is being sent to the server!");
		return;
	}

	var target = (e ? e.target : this);
	var form;

/*
//GM api test
GM_setValue("r00t_lastaction", "yes");
alert(GM_getValue("r00t_lastaction", ""));
GM_setValue("r00t_lastaction", "");*/

	if (target.tagName.toLowerCase() == 'input') {
		form = target.form;
	} else {
		form = findParentType(target, 'form');
	}
//alert("submit");
	if (form) {
		if (match = form.name.match("^search(\\d+)$")) {
			var i = (parseInt(match[1]) || 1) - 1;

//alert(fieldActions[i]);
//alert(fieldActions.toString() + "==" + fieldActions[i]);

			//r00t search clicked
//setCookie("r00t_lastaction", fieldActions[i], 5);
//alert(getCookie("r00t_lastaction"));

			GM_setValue("r00t_lastaction", fieldActions[i]);
//alert(GM_getValue("r00t_lastaction", ""));
		}
	}

	//submitting form to target.action
	//alert(target.action);

	form.submit();
}

function runGMAddData(start) {
	for (i = start; i < GM_num; i++) {
		if ((GM_addNewData[i] == null) || (GM_addNewData[i] == undefined)/* || (GM_addNewData[i].toString() == "")*/)
			continue;

		temp = GM_getValue("r00t_" + GM_names[i], "");

		if (temp == "")
			GM_data[i] = new Array();
		else
			GM_data[i] = temp.split("|");

		if (typeof GM_addNewData[i] == "object") {	//adding array data

			if (GM_addNewData[i].length == 0)
				continue;

			GM_newDataIndex[i] = new Array();
			var save = false;

			for (j = 0; j < GM_addNewData[i].length; j++) {
				GM_newDataIndex[i][j] = GM_data[i].indexOf(encodeURI(GM_addNewData[i][j]));

				if (GM_newDataIndex[i][j] == -1) {
					GM_newDataIndex[i][j] = GM_data[i].length;
					GM_data[i].push(encodeURI(GM_addNewData[i][j]));

					save = true;
				}
			}

			if (save)
				GM_setValue("r00t_" + GM_names[i], GM_data[i].join("|"))
		} else {					//adding string/number

			GM_newDataIndex[i] = GM_data[i].indexOf(encodeURI(GM_addNewData[i]));

			if (GM_newDataIndex[i] == -1) {
				GM_newDataIndex[i] = GM_data[i].length;
				GM_data[i].push(encodeURI(GM_addNewData[i]));

				GM_setValue("r00t_" + GM_names[i], GM_data[i].join("|"));
			}
		}

//alert("Item " + i + ": " + GM_addNewData[i] + " = " + GM_newDataIndex[i]);
	}
}

function runGMLinkAddData(start) {
	var data;
	var index;
	var combined;
	var hastime;
	var hascount;

	var startFieldPosition = 2;

	for (i = 0; i < GMlink_num; i++) {
		temp = GMlink_addNewData[i];
		if ((temp == null) || (temp == undefined) || (temp.length <= 1))
			continue;

		combined = "";
		hastime = false;
		hascount = temp[1];
//alert(temp.join(","));
		for (j = startFieldPosition; j < temp.length; j++) {
			if ((temp[j] == null) || (temp[j] == undefined) || (temp[j].toString() == ""))
				break;

			if (combined != "") combined += "=";

			if (j == temp[0]) { //time element, should always be on end
				hastime = true;
				continue;
			}

			combined += temp[j];
		}

		if (j != temp.length) {
//alert("Item " + i + " Link was skipped at " + j);
			continue;
		}
		if (hascount)
			combined += "=";

		temp = GM_getValue("r00t_" + GMlink_names[i], "");

		if (temp == "")
			GMlink_data[i] = new Array();
		else
			GMlink_data[i] = temp.split("|");

//alert("Link Item " + i + ": " + combined);

		if (hastime) {
			var time = GMlink_addNewData[i][GMlink_addNewData[i][0]];
			var date = new Date(time * 1000);
//alert("date: " + date);
			if (date.getTimeTime() < dayrollTime)
				date = new Date((time - 86400) * 1000);
//alert("date: " + date + ", datedate: " + date.getDateDate());
			date = date.getDateDate();

			GMlink_newDataIndex[i] = GMlink_data[i].indexOf(encodeURI(combined + date));

			if (GMlink_newDataIndex[i] == -1) {
				GMlink_newDataIndex[i] = GMlink_data[i].length;
				GMlink_data[i].push(encodeURI(combined + date));

				GM_setValue("r00t_" + GMlink_names[i], GMlink_data[i].join("|"));
			}
		} else if (hascount) {
			j = GMlink_data[i].startsWith(combined);

			if (j == -1) {
				j = GMlink_data[i].length;
				GMlink_data[i].push(encodeURI(combined + "1"));
			} else {
				temp = GMlink_data[i][j].split("=");
				temp[temp.length-1]++;
				GMlink_data[i][j] = temp.join("=");
			}
			GMlink_newDataIndex[i] = j;

			GM_setValue("r00t_" + GMlink_names[i], GMlink_data[i].join("|"));
		} else {
			GMlink_newDataIndex[i] = GMlink_data[i].indexOf(encodeURI(combined));

			if (GMlink_newDataIndex[i] == -1) {
				GMlink_newDataIndex[i] = GMlink_data[i].length;
				GMlink_data[i].push(encodeURI(combined));

				GM_setValue("r00t_" + GMlink_names[i], GMlink_data[i].join("|"));
			}
		}
	}
}

function QueryServer(query) {
	GM_xmlhttpRequest({
		method: 'POST',
		url: 'http://rveach.romhack.org/BvS/r00tlogger.php',
		headers: {'Content-type' : 'application/x-www-form-urlencoded'},
		data: encodeURI(query),

		onerror: function(response) {
			updateInProgress = false;
			alert("R00t Logger Failed!");
		},
		onload: function(response) {
			try {
				var text = response.responseText;
				updateInProgress = false;

				if ((text.startsWith("Saved;")) || (text.startsWith("SavedWarn;"))) {
					GM_setValue("r00t_lastsave", currentTime);

					for (var i = 0; i < GM_num; i++) {
						GM_setValue("r00t_" + GM_names[i], "");
					}
					for (var i = 0; i < GMlink_num; i++) {
						GM_setValue("r00t_" + GMlink_names[i], "");
					}

					if (showDialogResponse) {
						var divContent = document.createElement("div");
						divContent.id = "bvsR00tLogger";
						divContent.innerHTML = "<h1>R00t Logger</h1>Saved";
						document.body.appendChild(divContent);
					}

					if (text.startsWith("SavedWarn;")) {
						alert("R00t Logger Warning:\n\n" + text.substr(10));
					}
				} else if (text.startsWith("Wait;")) {
					GM_setValue("r00t_lastsave", currentTime);

					alert("R00t Logger Delayed Save:\n\n" + text.substr(5));
				} else if ((text == null) || (text.length == 0)) {
					alert("R00t Logger Error:\n\nUnknown Error");
				//} else if (text.length >= 400) {
				//	alert("R00t Logger Error:\n\nError Message too big to display!");
				} else {
					alert("R00t Logger Error:\n\n" + text);
				}
			} catch(e) {
				alert("Exception!\n\nError name: " + e.name + "\nError message: " + e.message);
			}
		}
	});
}

String.prototype.trim		= function() { return this.replace(/^\s+|\s+$/g,""); }
String.prototype.startsWith	= function(str) { return (this.match("^"+str) == str); }
String.prototype.removeHTML	= function() { return this.replace(/<[^>]*>/g, ""); }

Date.prototype.getDOY = function() {
	var onejan = new Date(this.getFullYear(),0,1);
	return Math.ceil((this - onejan) / 86400000);
}

Date.prototype.getDateDate = function() {
	return this.getFullYear() + "-" + (this.getMonth()+1) + "-" + this.getDate();
}

Date.prototype.getTimeTime = function() {
	return this.getHours()*60*60+this.getMinutes()*60;
}

Array.prototype.startsWith	= function(str, start) {
	var rtrn = -1;
	if (start == undefined) start = 0;

	for (var i = start; i < this.length; i++) {
		if (this[i].startsWith(str)) {
			rtrn = i;
			break;
		}
	}

	return rtrn;
}

/*function setCookie(c_name, value, expiredays) {
	var exdate=new Date();

	exdate.setDate(exdate.getDate()+expiredays);

	document.cookie=c_name+ "=" +escape(value) + ((expiredays==null) ? "" : ";expires="+exdate.toGMTString());
}

function getCookie(c_name) {
	if (document.cookie.length>0) {
		c_start=document.cookie.indexOf(c_name + "=");

		if (c_start != -1) {
			c_start=c_start + c_name.length+1;
			c_end=document.cookie.indexOf(";",c_start);

			if (c_end == -1) c_end=document.cookie.length;
			return unescape(document.cookie.substring(c_start,c_end));
		}
	}

	return "";
}*/

function findParentType(node, type) {
	var parent = node;
	type = type.toLowerCase();

	while (parent != null) {
		if (parent.tagName.toLowerCase() == type) break;

		parent = parent.parentNode;
	}

	return parent;
}

function attachEventToForm(element, eventfunction) {
	element.wrappedJSObject.submit = eventfunction;			//captures all wrappedJSObject.submit(), even GMs
	element.addEventListener('submit', eventfunction, true);	//doesn't seem to capture anything
	element.addEventListener('click',  eventfunction, true);	//captures link/form click

	//how to capture all elem.subtmit(), even GMs???????????




	/*element.submit = function(){ alert('form.submit'); };
	element.wrappedJSObject.submit = function(){ alert('form.wrapped.submit'); };
	element.addEventListener('submit', function(){ alert('eventlistener.submit'); }, true);
	element.addEventListener('click',  function(){ alert('eventlistener.click'); }, true);

	window.addEventListener('submit', function(e) {
                                alert('window.eventlistener');
                                e.preventDefault();
                            }, false);
	document.addEventListener('submit', function(e) {
                                alert('document.eventlistener');
                                e.preventDefault();
                            }, false);

	unsafeWindow.HTMLFormElement.prototype.submit = function(){ alert('unsafeWindow.HTMLFormElement.prototype'); };//*/

}

function injectScript(script) {
	var head = document.getElementsByTagName("head")[0];
	var node = document.createElement("script");
	node.type = "text/javascript";
	node.innerHTML = script;
	head.appendChild(node);
}