// ==UserScript==
// @name           Last.fm - Numerizm
// @namespace      www.daddy.sk
// @description    Adds numeric information to last.fm pages, such as: Numeric compatibility, track enumeration and more
// @include        http://www.last.fm/*
// ==/UserScript==

scriptName		= 'Last.fm - Numerizm';
versionURL		= "http://gm.daddy.sk/scripts/versions/lastfm_-_numerizm.txt";	// URL to file containing version number of the script stored on owners server.
sourceURL		= "http://gm.daddy.sk/scripts/lastfm_-_numerizm.user.js";		// URL to the source of the scripts latest version
homepageURL		= "http://gm.daddy.sk/"										// URL of the scripts homepage.
msgNodeXPath	= "//body"/*"//div[@id='LastContent3']"*/; 							// XPath to element, in which should the messages be displayed.
currentVersion	= 4;														// Version of the script contained in this file. ALWAYS update along with the information contained in versionURL
checkForUpdatesByDefault	= true;
greaseMonkeyURL	= "http://www.greasespot.net/";								// Greasemonkey homepage
updateCheckFrequency 		= 0; 											// How many days should pass between two checks for updates. (0 means: check always)
debugMode		= true;

// Evaluate xPath against the given element or document if no element is given.
function xPath(query, doc) {
    var xResult, arrResult = [];
	if (!doc) {
		doc = document;
	}
	xResult = document.evaluate(query, doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);	
	for (i = 0; item = xResult.snapshotItem(i); i++) {
		arrResult.push(item);
	}
	return arrResult;
}

// Executes xpath query on given html (for example, the result of getUrl function)
function xPathOnHTML(query, code) {
	var divHelper;
	divHelper = document.createElement('div');
	divHelper.innerHTML = code;
	return xPath("." + query, divHelper);
}

// Get the contents of URL via xhttprequest
function getURL(URL, fOnLoad, fOnError){
    GM_xmlhttpRequest({
        method: 'GET',
        url: URL,
        onload: fOnLoad,
		onerror: fOnError
		});
}

// Log the message to the console if debugging is turned on (debugMode variable)
function log(msg) {
	if (debugMode) {
		GM_log(msg);
	}	
}

// Check whether all required GreaseMonkey functions are available.
function checkGMVersion() {
	if (!GM_xmlhttpRequest || !GM_registerMenuCommand || !GM_setValue || !GM_getValue) {
		msgNode = xPath(msgNodeXPath)[0];
		msg = "<b><a href=\"" + homepageURL + "\" target=\"_blank\">" + scriptName + "</a></b>: Please install latest version of the Greasemonkey. You can get it <a href=\"" + greaseMonkeyURL + "\">here</a>.";
		msgDiv = document.createElement("div");
		msgDiv.className = "gmVersionMsg";
		msgDiv.innerHTML = msg;
		msgNode.insertBefore(msgDiv, msgNode.firstChild);
		return false;
	}
	return true;
}

// Calculates number of days between two dates.
// Used to determine whether time has come to check for updates.
function daysBetween(date1, date2) {
    var ONE_DAY = 1000 * 60 * 60 * 24
    return Math.round(Math.abs(date1.getTime() - date2.getTime())/ONE_DAY)
}

function checkScriptVersion() {
    var now, lastVersionCheck, daysPassed;
	
	now = new Date();
    lastVersionCheck = GM_getValue('lastVersionCheck', 0);
	daysPassed = daysBetween(now, new Date(lastVersionCheck));
	log('lastVersionCheck:	' + lastVersionCheck);
	log('daysPassed:	' + daysPassed);
	
	if(daysPassed < updateCheckFrequency) {
		return;
    }
	
    getURL( versionURL,
			function(responseDetails) {
	            var latestVersion, responseText, msgnode, versionMsg;
				
				responseText = responseDetails["responseText"];
				latestVersion = parseInt(responseText);
	            GM_setValue('lastVersionCheck', String(now));
				if(latestVersion > currentVersion) {
	                log('New version available');
					msgnode = xPath(msgNodeXPath)[0];
					versionMsg = "The <b><a href=\"" + homepageURL + "\" target=\"_blank\">" + scriptName + "</a></b> Greasemonkey Script has been updated. Click <a href=\"" + sourceURL + "\">here</a> to get the latest version.";
					versionDiv = document.createElement("div");
					versionDiv.className = "gmVersionMsg";
					versionDiv.innerHTML = versionMsg;
					msgnode.insertBefore(versionDiv, msgnode.firstChild);
	            }
			}, 
			null
		);
}

function checkForUpdatesOff() {
    GM_setValue('checkForUpdates', false);
    document.location.reload();
}

function checkForUpdatesOn() {
    GM_setValue('lastVersionCheck', 0);
	GM_setValue('checkForUpdates', true);
    document.location.reload();
}

function checkForUpdatesOnce() {
    GM_setValue('lastVersionCheck', 0);
	checkScriptVersion();
}

GM_addStyle(
	".gmVersionMsg { margin:10px; color:#545454; font-family:\"Lucida Grande\",Arial,Helvetica,Verdana,sans-serif; font-size:12px; line-height:1.4em; text-align:center; background-color: white; }"
)

if (!checkGMVersion()) {
	return;
}

var checkForUpdates;
checkForUpdates = GM_getValue('checkForUpdates', checkForUpdatesByDefault);

if (checkForUpdates) {
	checkScriptVersion();
	GM_registerMenuCommand(scriptName + ": Stop checking for updates", checkForUpdatesOff);
} else {
	GM_registerMenuCommand(scriptName + ": Check for updates automatically", checkForUpdatesOn);
}

GM_registerMenuCommand(scriptName + ": Check for updates now", checkForUpdatesOnce);

GM_setValue('lastVersionCheck', 0); //!!

// ---------------------------------- //
//    Numeric Compatibility    //
// ---------------------------------- //
window.addEventListener(
	'load',
	function() {
		setTimeout(
			function () {
				var graph, rating;
				//rating = document.getElementById("tomRating");//tomGraph");
				log('Let\'s see the rating');
				rating = xPath("//div[@id='tasteometer']/span")[0];
				
				if (rating != null)
				{
					var body, compatibility, pos, compatibilityDisp;
					var styleElement = "width: ";
					body = rating.innerHTML;
					log("Found. innerHTML: \n" + rating.innerHTML);
					pos = body.indexOf( styleElement );
					compatibility = body.substring( pos + styleElement.length, body.indexOf('%' , pos) );					
					log("compatibility: " + compatibility);
					
					log('Let\'s see the graph');
					//graph = document.getElementById("tomGraph");
					graph = xPath("//div[@id='tasteometer']/p/strong[2]")[0];

					if (graph != null) {
						log("Found. innerHTML: \n" + graph.innerHTML);
						//graph.innerHTML = "<center><b style=\"color: white;\">" + compatibility + "%</b></center>";
						graph.innerHTML += ' (' + compatibility + '%)';
					} else {
						log('Rating found, but no graph.')
					}
				} else {
					log('Rating not found.')
				}
			},
		500);
	},
  false
);

// ---------------------------------- //
// Recent tracks enumeration //
// ---------------------------------- //
var location, tracksPlayedCount, tracks, positionTd, pageNumber;
RECENT_TRACKS_REGEX = /^http:\/\/www\.last\.fm\/user\/\w+\/charts\/\?charttype=recenttracks/;
RECENT_TRACKS_PER_PAGE = 50;

location = window.location.toString();
log("window.location:	" + location);

if (location.match(RECENT_TRACKS_REGEX)) {
	log('recent')
	tracksPlayedCount = xPath("//div[@id='avatarPanel']/div[@class='c']/p/span/span[@class='nowrap']")[0].innerHTML.replace(',','').replace(' ','');
	pageNumber = xPath("//div[@id='LastContent3']/div[@class='pagination']/span[@class='selected']")[0].innerHTML;
	tracks = xPath("//table[@id='deletablert']/tbody/tr");
	log('tracksPlayedCount:	' + tracksPlayedCount);
	log('pageNumber:	' + pageNumber);
	log('tracks: ' + tracks.length);
	for (i in tracks) {
		positionTd = document.createElement('td');
		positionTd.setAttribute('class', 'position');
		positionTd.setAttribute('style','border-right:1px solid #B5B5B5;');
		positionTd.innerHTML = tracksPlayedCount - i - (pageNumber-1)*RECENT_TRACKS_PER_PAGE;
		tracks[i].insertBefore(positionTd, tracks[i].firstChild);
	}
} else {
	log('not recent')
}
