// ==UserScript==
// @name           MinbariUtilities
// @namespace      http://www.minbarifederation.net
// @description    Adds in special features for Minbari Players
// @identifier     http://kiserai.net/~neutralizer/minbariutilities.user.js
// @date           2009-04-28
// @include        http://alpha.astroempires.com/*
// @exclude        http://forum.astroempires.com/*
// @exclude        *.astroempires.com/home.aspx*
// @exclude        *.astroempires.com/login.aspx*
// ==/UserScript==

var scriptVersion=6.0;
var scriptName = "minbariutilities";
var currentPage = location.href; //Get current URL.
var scriptLink = "http://kiserai.net/~neutralizer/" + scriptName + ".user.js";

/*

==UpdateText==
Release Notes (Version 6.0)
<br/><br/>4/28/2009
<br/>Updated Minbari Menu
<br/>Fixed base and empty astro list
<br/>- neutralizer
<br/><br/>12/23
<br/>Removed: News Screen
<br/><br/>6/30
<br/>Bug Fix: Fixed a few lingering bugs. Hopefully fixed the IE color bug in the quote system as well.
(Version 4.9)
<br/><br/>6/22
<br/>Bug Fix: Fixed some bugs that breaks the quote function.
<br/>Minor Tweak: Changed the auto-linking of URLs to open in a new tab by default.
(Version 4.7)
<br/><br/>6/20-6/21
<br/>Bug Fix: Made it work again. And again. And again. It really works this time. I hope.
<br/>Tweaked Feature: Added a link to the latest script version on the menu bar.
<br/>Tweaked Feature: Changed look of new Quote function.
<br/>New Feature: Added ability to quote posts on boards.
==/UpdateText==

*/


/*
##################################################################################################################
Function: insertNotification

Use: This function will run anytime the script needs to deliver a message to a user. It will add the appropriate 
	style to the message, then open a message box at the top of the screen to alert the user. 

Calls: Called from other functions.

Credit: This function came from the AE Extras script. I bent it for my own needs. I did a lot of re-writing, 
	but at its core, its still shamelessly ripped off. 
##################################################################################################################
*/
function insertNotification(message){
	GM_addStyle('#gm_update_alert {'
        	+'    position: relative;'
        	+'    z-index: 99;'
        	+'    top: 0px;'
        	+'    left: 0px;'
        	+'    width: 100%;'
        	+'    background-color: Black;'
        	+'    text-align: center;'
        	+'    font-size: 11px;'
        	+'    font-family: Tahoma;'
        	+'    border: solid 1px;'
        	+'    margin-bottom: 10px;'
        	+'}'
    	+'#gm_update_title {'
        	+'    weight:bold;'
        	+'    color:orange;'
        	+'}');

    	var notification = document.createElement("div");
    	notification.setAttribute('id', 'gm_update_alert');
    	notification.innerHTML = ''
    	+'    <div id="gm_update_title">MinbariMenus Notification</div>'
    	+ '<br>' + message;
    	document.body.insertBefore(notification, document.body.firstChild);

}
//################################################################################################################


/*
##################################################################################################################
Function: checkForUpdate

Use: This function will run once per page load, check to see if it has checked within the last hour. If it
	has checked, it won't check again. If it has not checked recently, it will check. If the version on
	the server is greater than the version running right now, it will send the user a notification via the
	insertNotification(message) function.

Calls: Called once per page load.

Credit: This function came from the AEExtras script. I bent it for my own needs. I did a lot of re-writing, 
	but at its core, its still shamelessly ripped off.
##################################################################################################################
*/
function checkForUpdate(){
    var lastCheck = parseInt(GM_getValue('minLastCheck', 0));
    var d = new Date();
    var currentTime = Math.round(d.getTime() / 1000); // Unix time in seconds

       	if (currentTime > (lastCheck + (3600))) {   //Check every hour          
        	GM_setValue('minLastCheck', currentTime);    //Set time of check
		GM_xmlhttpRequest({
            		method: 'GET',
            		url: 'http://kiserai.net/~neutralizer/'+scriptName+'.user.js?format=txt',
            		headers: {
                	'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey','Accept': 'text/plain',
            		},
            		onload: function(responseDetails) {
                		var text = responseDetails.responseText;

				var versionLocation = (text.indexOf("scriptVersion="));
                		var siteVersion = text.substring(versionLocation+14,versionLocation+17);
                		var siteUpdateText = text.substring(text.indexOf("==UpdateText==")+14,text.indexOf("==/UpdateText=="));
				//GM_log("Current Version: "+scriptVersion+" Site Version: "+siteVersion);
                		if(parseFloat(siteVersion) > scriptVersion) {
                    			var message = 'There is an update available for "'+scriptName+'" <br>'
                    			+'    You are currently running version '+scriptVersion
                    			+'. The newest version is '+siteVersion+'.</br>'
                    			+'    </br>'+ siteUpdateText +'</br>'
                    			+'    </br>'
					+'<span id="gm_update_link"><a href="http://kiserai.net/~neutralizer/'+scriptName+'.user.js">'
					+ 'Click here to update your installation.</a></span>';
                    			insertNotification(message);
					var button = document.getElementById('gm_update_link');
                    			button.addEventListener('click', function(event){
						document.body.removeChild(document.getElementById('gm_update_alert'));
					}, true);          			
            			}
                
			}
	
		});
	}
}
//################################################################################################################









/*
##################################################################################################################
Function: drakeProof

Use: This function will search each page for naked URLs. That is to say, when Drake posts URLS without making them
	clickable, this function will fix his laziness for everyone else.

Calls: Called once during script. The call will perform the search for naked URLS.

Credit: This script comes from Greasemonkey Hacks, By Mark Pilgrim Copyright 2006. Original code by Aaron Boodman

Last Update: 6/22/08
##################################################################################################################
*/
function drakeProof(){
	var urlRegex = /\b(https?:\/\/[^\s+\"\<\>]+)/ig;
	var snapTextElements = document.evaluate("//text()[not(ancestor::a) " + 
		"and not(ancestor::script) and not(ancestor::style) and not(ancestor::textarea) and " + 
		"contains(translate(., 'HTTP', 'http'), 'http')]", 
		document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
	for (var i = snapTextElements.snapshotLength - 1; i >= 0; i--) {
		var elmText = snapTextElements.snapshotItem(i);
		if (urlRegex.test(elmText.nodeValue)) {
			var elmSpan = document.createElement("span");
			var sURLText = elmText.nodeValue;
			elmText.parentNode.replaceChild(elmSpan, elmText);
			urlRegex.lastIndex = 0;
			for (var match = null, lastLastIndex = 0;
				 (match = urlRegex.exec(sURLText)); ) { 
				elmSpan.appendChild(document.createTextNode(
				sURLText.substring(lastLastIndex, match.index))); 
				var elmLink = document.createElement("a");
				elmLink.title = 'DCR-proofed by MinbariMenu GM script!';
				elmLink.style.textDecoration = 'none';
				elmLink.style.borderBottom = '1px dotted red';
				elmLink.setAttribute("href", match[0]); 
				elmLink.setAttribute("target", "_blank");
				elmLink.appendChild(document.createTextNode(match[0])); 
				elmSpan.appendChild(elmLink); 
				lastLastIndex = urlRegex.lastIndex;
			}
			elmSpan.appendChild(document.createTextNode(
				sURLText.substring(lastLastIndex)));
			elmSpan.normalize();
		}
	}

}
//################################################################################################################







/*
##################################################################################################################
Function: insertMinbariMenu

Use: Inserts a guild-specific menu in AstroEmpires prior to the system clock. This should put it as near to the regular 
	AE menu as possible, without restricting myself to searching for a specific menu item that may or may not exist 
	in the future.

Calls: Called once during script. The call will do the insertion of the menu.

Last Update: 6/21/08
##################################################################################################################
*/

function insertMinbariMenu(){
	var html = '<br/>Minbari: <span class="minbariMenu"><a href="http://www.minbarifederation.com" target="_blank" id="header-purple">' 
		+'Forums</a> - <a href="http://widget.mibbit.com/?server=irc.lucidchat.net&channel=%23min&forcePrompt=true&promptPass=true&settings=39dcaae8764ad49e5e36ebd62c57cd83" target="_blank" '
		+' id="header-purple">Chat Room</a> - <a href="http://lueshi.dontexist.net/genome/"'
		+' target="_blank" id="header-purple">Database</a>'
		+' - <a href="' + scriptLink + '" id="header-purple">GM Script</a></span><br/>';
        var findServerTime= document.evaluate("//small[starts-with(text(),'Server time')]",
	   	document,
	        null,
	        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
	        null); 
	var lastNavigation = findServerTime.snapshotItem(0);
	var minbariMenu = document.createElement('span'); 

	GM_addStyle('.minbariMenu { border-width: 1px; border-style: solid; background-color: #333; border-color: #FFF;}'); 
		//This style changes the color of the Minbari menu bar.

	if(findServerTime.snapshotLength==0)
		return;

	minbariMenu.setAttribute('align','center'); 
	minbariMenu.innerHTML = html;

	if(lastNavigation) {
        	lastNavigation.parentNode.insertBefore(minbariMenu,lastNavigation.previousSibling);
        	var lineBreak = document.createElement('br');
        	lastNavigation.parentNode.insertBefore(lineBreak,lastNavigation);
        	lastNavigation.parentNode.insertBefore(lineBreak,minbariMenu);
	}
}
//################################################################################################################










/*
##################################################################################################################
Function: insertSystemBaseList

Use: Inserts a list of bases found within a System page on that System page. This puts all of the bases together 
	in one section on the page, making it easier to see who is in a system, and scout the important planets.
	The menu will only attempt to be made if A> You are on the System Page, and B> There are bases in that
	system. 

Calls: Called once during script. The call will do the insertion of the table.
##################################################################################################################
*/

function insertSystemBaseList(){
	var playersInSystem = document.evaluate(
	    '//a[@title][not(contains(@id,"_c"))]/text()',
	    document,
	    null,
	    XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
	    null);
	var basesInSystem = document.evaluate(
	    '//a[starts-with(@href,"base.aspx?")]/@href',
	    document,
	    null,
	    XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
	    null);    
	var coordsInSystem = document.evaluate(
	    '//a[@title][not(contains(@id,"_c"))]/@id',
	    document,
	    null,
	    XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
	    null);   
	var uninhabitedPlanetsInSystem = document.evaluate(
	    '//span[@id and @style]/@id',
	    document,
	    null,
	    XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
	    null);   
	var uninhabitedLinks = document.evaluate(
	    '//span[@id and @style]/@id',
	    document,
	    null,
	    XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
	    null); 

	var totalBases = basesInSystem.snapshotLength; 
	var totalPlanets = uninhabitedPlanetsInSystem.snapshotLength;
	var x;
	var html = "<tr><td><b>Players with bases in System</b></td><td>"
		+"<b>Uninhabited Planets</b></td></tr>";
	var mapPage = currentPage.match(/map\.aspx\?.+/);
	var systemPage = currentPage.match(/A.+:.+:.+:.+/);


	if (mapPage && !systemPage ){

		if (totalBases || totalPlanets){
		
	
			for (x = 0; x < totalBases || x < totalPlanets; x++){
				if (x >= totalBases) {
					var playerName = ""
					var baseLink = ""
					var coords = ""
				}
				else {
					var playerName = playersInSystem.snapshotItem(x).textContent;
					var baseLink = basesInSystem.snapshotItem(x).textContent;
					var coords = coordsInSystem.snapshotItem(x).textContent;
					coords = ' (' + coords.slice(0,12) + ')';
				}

				if (x < uninhabitedPlanetsInSystem.snapshotLength) {
					var uninhabitedPlanets = uninhabitedPlanetsInSystem.snapshotItem(x).textContent;
					uninhabitedPlanets = uninhabitedPlanets.slice(0,12);
					var unihabitedPlanetLinks = 'map.aspx?loc=' + uninhabitedLinks.snapshotItem(x).textContent.slice(0,12);
					html = html + '<tr><td><a href="' + baseLink + '">'
						+ playerName + coords + '</a></td><td><a href="' + unihabitedPlanetLinks + '">'
						+ uninhabitedPlanets + '</a></td></tr>';
				}
				else {
				html = html + '<tr><td><a href="' + baseLink + '">' + playerName 
				+ coords + '</a></td></tr>';
				}
			}
	

		var tables = document.evaluate(
	    		"//table[@class='system']",
	    		document,
	    		null,
	    		XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
	    		null);
	    		if(tables.snapshotLength==0)
	    			return;
	    	var systemTable = document.evaluate(
	    		"//body",
	    		document,
	    		null,
	    		XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
	    		null);
	    		var newTable = document.createElement('table');
	    		newTable.setAttribute('width',(tables.snapshotItem(0).getAttribute("width")/2));
	    		newTable.setAttribute('align','center');
	    		newTable.setAttribute('class','system');
	    		newTable.innerHTML = html;
		systemTable = systemTable.snapshotItem(0);
	    		if(systemTable){
				systemTable.appendChild(newTable);
	        		var lineBreak = document.createElement('br');
	        		newTable.parentNode.insertBefore(lineBreak,newTable);
            		}
		}
	}
}
//################################################################################################################







/*
##################################################################################################################
Function: insertQuotes

Use: This function will add a quote function for each post on the boards.

Calls: Once per board page load.

Last Update: 6/30/08
##################################################################################################################
*/
function insertQuotes(){
	var posts = document.evaluate(
		'//td[contains(@style, "padding: 10px")]',
	    document,
	    null,
	    XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
	    null);

	var checkLocation = document.evaluate(
	    '//td/a[text()="Msg Player" and not(contains(../@style, "padding: 10px"))] | //td[@class="red" and text()="System"]',
	    document,
	    null,
	    XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
	    null);

	var tableHeader = document.evaluate(
	    '//th[contains(text(), "Date")]',
	    document,
	    null,
	    XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
	    null);
	
	var names = document.evaluate(
	    '//td/a[contains(@href, "?player=")][not(contains(ancestor::td/@style, "padding: 10px"))] | //td[@class="red" and text()="System"]',
	    document,
	    null,
	    XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
	    null);


	tableHeaderNode = tableHeader.snapshotItem(0);

	tableHeaderNode.setAttribute("width", "20%");
	
	var quoteHeader = document.createElement("th");
	quoteHeader.setAttribute("width", "10%");
	tableHeaderNode.parentNode.appendChild(quoteHeader);		 	   		

	for (var i = posts.snapshotLength - 1; i >= 0; i--) {

		var postNode = posts.snapshotItem(i);
		var postContents = postNode.textContent;
		var postRow = postNode.parentNode;
		var checkNode = checkLocation.snapshotItem(i);
		postNode.setAttribute("colspan", postNode.colSpan + 1);

		

		if (!postContents.match("Copy from " && " Messages") &&
			!currentPage.match("announcements") && !names.snapshotItem(i).textContent.match("System")) {
			postNode.setAttribute("id", "post" + i);

			var elmTd = document.createElement("td");
			checkNode.parentNode.parentNode.appendChild(elmTd);

			var quoteButton = document.createElement("input");
   			quoteButton.type="button";
    			quoteButton.value="Quote";
			quoteButton.setAttribute("id", "quote" + i);
			quoteButton.setAttribute("test", i);
			elmTd.appendChild(quoteButton); 



    			document.getElementById("quote" + i).addEventListener('click', function() {
				var postNumber = this.id.slice(5);				
				var postContents = document.getElementById("post" + postNumber).textContent;
				var textBox = document.getElementById("body");
				var currentName = names.snapshotItem(postNumber).textContent;


				if (textBox.value) {
					textBox.value += '\n\n[color=\'#BEBEBE\']<<<[size=\'1\'][b]' + currentName + ' said:[/b] [i]"'
						+ postContents + '"[/i][/size]>>>[/color]\n\n';
					javascript:scroll(0,0);
					textBox.focus();

				}
				else {
					textBox.value += '[color=\'#BEBEBE\']<<<[size=\'1\'][b]' + currentName + ' said:[/b] [i]"'
						+ postContents + '"[/i][/size]>>>[/color]\n\n';
					javascript:scroll(0,0);
					textBox.focus();
				}


    			}, false);

		}
		else {
			var elmTd = document.createElement("td");
			checkNode.parentNode.parentNode.appendChild(elmTd);
		}
	
	var cleanUp = document.evaluate(
	    '//th[@colspan="4"] | //td[@colspan="4"] | //td[a/text()="Next" and @align="right"] | //td[text()="System"]',
	    document,
	    null,
	    XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
	    null);


	}
	for (var j = cleanUp.snapshotLength - 1; j > -1; j--) {	

		if (cleanUp.snapshotItem(j).textContent.match("System")) {
		var elmTd = document.createElement("td");
		cleanUp.snapshotItem(j).parentNode.appendChild(elmTd);
		}
		else {
		cleanUp.snapshotItem(j).colSpan += 1;
		}
	}
}
//################################################################################################################



if (currentPage.match("/board.aspx")) {
	insertQuotes();
}



insertMinbariMenu();
insertSystemBaseList();
checkForUpdate();
drakeProof();




