// ==UserScript==
// @name		RYM enhancer enhanced
// @namespace	http://rateyourmusic.com/
// @description	Adds a lot of new features to RYM
// @include	http://rateyourmusic.com/*
// @include	http://www.rateyourmusic.com/*
// ==/UserScript==//

var url = document.URL;	
var gUrlSubstr = url.split("/"); /*Sets global array containing the URL, used in various functions*/

/*This sets Menu Commands for the user to choose which functions should be used*/
GM_registerMenuCommand("Use 1-10 scale for ratings", sRatingsDuplicator);
GM_registerMenuCommand("Use 1-10 scale for star hover (title) text", sStarRatingsDuplicator);
GM_registerMenuCommand("Add average ratings to artist pages", sAverageCalculator);
GM_registerMenuCommand("Add colour to ratings", sColorizer);
GM_registerMenuCommand("Highlight rated records in lists & charts", sChartsRatedHighlighter);
GM_registerMenuCommand("Highlight owned records in lists & charts", sChartsOwnedHighlighter);
GM_registerMenuCommand("Highlight wishlist records in lists & charts", sChartsWishlistedHighlighter);

/*This checks user preferences and calls each function depending on them*/
if(GM_getValue('averageCalculator', 1))		{averageCalculator();}
if(GM_getValue('colorizer', 1))				{colorizer();}
if(GM_getValue('ratingsDuplicator', 1))		{ratingsDuplicator();}
if(GM_getValue('starRatingsDuplicator', 1))	{starRatingsDuplicator();}
chartsHighlighter();

/*This functions are switches for the boolean parameters that control user options*/
function sRatingsDuplicator()
{
	if(!(GM_getValue('ratingsDuplicator', 0)))
		{GM_setValue('ratingsDuplicator',1);}
	else
		{GM_setValue('ratingsDuplicator',0);}
}
function sStarRatingsDuplicator()
{
	if(!(GM_getValue('starRatingsDuplicator', 0)))
		{GM_setValue('starRatingsDuplicator',1);}
	else
		{GM_setValue('starRatingsDuplicator',0);}
}
function sAverageCalculator()
{
	if(!(GM_getValue('averageCalculator', 0)))
		{GM_setValue('averageCalculator',1);}
	else
		{GM_setValue('averageCalculator',0);}
}
function sColorizer()
{
	if(!(GM_getValue('colorizer', 0)))
		{GM_setValue('colorizer',1);}
	else
		{GM_setValue('colorizer',0);}
}
function sChartsRatedHighlighter()
{
	if(!(GM_getValue('chartsRatedHighlighter', 0)))
		{GM_setValue('chartsRatedHighlighter',1);}
	else
		{GM_setValue('chartsRatedHighlighter',0);}
}
function sChartsOwnedHighlighter()
{
	if(!(GM_getValue('chartsOwnedHighlighter', 0)))
		{GM_setValue('chartsOwnedHighlighter',1);}
	else
		{GM_setValue('chartsOwnedHighlighter',0);}
}
function sChartsWishlistedHighlighter()
{
	if(!(GM_getValue('chartsWishlistedHighlighter', 0)))
		{GM_setValue('chartsWishlistedHighlighter',1);}
	else
		{GM_setValue('chartsWishlistedHighlighter',0);}
}

/*End of switch functions*/

function ratingsDuplicator() /*Duplicates each 0.5-5 rating on the site*/
{
	function parseXpath(xpathQuery) /*Duplicates each rating value for each xpath query*/
	{
		GM_log('1');
		for(var i=0; i<xpathQuery.snapshotLength; i++)
		{
			GM_log('2');
			var target = xpathQuery.snapshotItem(i);
			var rating = target.textContent;
			if(!isNaN(rating))
			{
				GM_log('3');
				rating*=2;
				if((rating-Math.floor(rating))==0)
					{target.textContent = rating.toFixed(0);}
				else
					{target.textContent = rating.toFixed(2);}
			}
		}
	}
	if(gUrlSubstr[3]=="artist")
	{
		parseXpath(xpath('//td/div[@class="medium"]'));									/*Album rating*/					
		parseXpath(xpath('//div[@class="medium"]/span'));								/*Grey album ratings*/
		parseXpath(xpath('//div[@class="small"]/a[@class="artist_rate"]'));				/*My rating*/
	}
	else if(gUrlSubstr[3]=="release")
	{
		parseXpath(xpath('//table[@class="mbgen"]/tbody/tr/td/span[not(@id="prediction")]'));
		parseXpath(xpath('//a[@class="ratingbutton"]')); 							/*Rating buttons*/
		parseXpath(xpath('//a[@class="ratingbuttonhc"]')); 							/*Used rating button*/
		parseXpath(xpath('//tbody/tr/td[@style="width: 3em;"]')); 					/*Rating distributions*/
		parseXpath(xpath('//span[@id="ratingtext"]')); 								/*Rating text near stars*/
	}
	else if(gUrlSubstr[3]=="charts"||(gUrlSubstr[3].slice(0,11))=="customchart")
		{parseXpath(xpath('//a/b[1]'));}												/*Small ratings at charts*/
	else if(gUrlSubstr[3].slice(0,1)=="~")
		{parseXpath(xpath('//a[@class="medium"]'));}									/*Rating distribution at user sites*/
}

function starRatingsDuplicator() /*Changes stars's alternative text to 1-10 ratings*/
{
	starPathQuery = xpath('//img[@width="77"]'); /*Star images*/
	for(var i=0; i<starPathQuery.snapshotLength; i++)
	{
		var target = starPathQuery.snapshotItem(i);
		var starSrc = target.src;
		target.title = starSrc.substring((starSrc.lastIndexOf('/'))+1, starSrc.lastIndexOf('.'))+" stars";
	}
}

function averageCalculator() /*Calculates average ratings for an artist and individual categories*/
{
	if(gUrlSubstr[3]=="artist")
	{
		function categoryAverage(category)
		{
			if(category)
			{
				var tBody = category.getElementsByTagName("tbody")[0];
				var rows = tBody.getElementsByTagName("tr");
				var average=0, i=2, errors=0;
				for(var row=null; row=rows[i]; i++)
				{
					var cell = row.getElementsByTagName("td")[6];
					var rating = cell.textContent;
					if(!isNaN(parseFloat(rating))) {average+=parseFloat(rating);}
					if(isNaN(parseFloat(rating))) {++errors;}
				}
				globalAverage+=average;
				globalRecordNumber+=(i-2-errors);
				average/=(i-2-errors);
				var row = document.createElement("tr");
				for(var e=0; e<8; e++)
				{
					cells = document.createElement("td");
					cells.style.background = 'rgb(255,255,204)';
					if(e==1)
					{
						cellText = document.createTextNode("Average rating: ");
						cells.appendChild(cellText);
						cells.style.fontWeight = 'bold';
					}
					else if(e==6)
					{
						var div = document.createElement('div');
						div.className = 'medium';
						divText = document.createTextNode(average.toFixed(2));
						div.appendChild(divText);
						cells.appendChild(div);
					}
					row.appendChild(cells);
				}
				category.appendChild(row);
			}
		}
		var globalAverage=0, globalRecordNumber=0;
		categoryAverage(document.getElementById("album_disc_s"));
		categoryAverage(document.getElementById("album_disc_e"));
		categoryAverage(document.getElementById("album_disc_c"));
		categoryAverage(document.getElementById("album_disc_i"));
		categoryAverage(document.getElementById("album_disc_b"));
		categoryAverage(document.getElementById("album_disc_d"));
		globalAverage /= globalRecordNumber;
		var row = document.createElement("tr");
		var td = document.createElement("td");
		var tdText = document.createTextNode("Rating");
		td.appendChild(tdText);
		row.appendChild(td);
		td = document.createElement("td");
		if(GM_getValue('ratingsDuplicator', 1))
			{tdText = document.createTextNode((globalAverage*2).toFixed(2));}
		else
			{tdText = document.createTextNode(globalAverage.toFixed(2));}
		td.appendChild(tdText);
		row.appendChild(td);
		var table = document.getElementsByTagName("table")[0];
		if(table.getElementsByTagName("table")[1])
			{secondTable=table.getElementsByTagName("table")[1];}
		else
			{secondTable=table.getElementsByTagName("table")[0];}
		secondTable.appendChild(row);
	}
}

function colorizer() /*Gives color to ratings*/
{
	function applyColor(xpathQuery)
	{
		for(var i=0; i<xpathQuery.snapshotLength; ++i)
		{
			var div = xpathQuery.snapshotItem(i);
			var value = div.textContent;
			if(!isNaN(value))
			{
				if(value<2) 		{div.style.color="#ff3333";}
				else if(value<3.5)	{div.style.color="#ffcc33";}
				else 				{div.style.color="#339900";}
			}
		}
	}
	
	if(gUrlSubstr[3]=="artist")
	{
		applyColor(xpath('//td/div[@class="medium"]'));									/*Album rating*/					
		applyColor(xpath('//div[@class="medium"]/span'));								/*Grey album ratings*/
	}
	else if(gUrlSubstr[3]=="release")
	{
		applyColor(xpath('//span[@style="font-size: 1.3em; font-weight: bold;"]'));	/*Rating*/
		applyColor(xpath('//span[@style="font-size: 1.3em; font-weight: bold; color: rgb(51, 136, 51);"]')); 
																						/*Friends rating*/
	}
	else if(gUrlSubstr[3]=="charts"||(gUrlSubstr[3].slice(0,11))=="customchart")
		{applyColor(xpath('//a/b[1]'));}												/*Small ratings at charts*/
	else if(gUrlSubstr[3].slice(0,1)=="~")
		{applyColor(xpath('//a[@class="medium"]'));}									/*Rating distribution at user sites*/
}

function chartsHighlighter() /*Highlights rated records from a chart page*/
{
	if(gUrlSubstr[3]=="charts"||gUrlSubstr[3]=="list"||(gUrlSubstr[3].slice(0,11))=="customchart")
	{
		var div = document.getElementsByTagName('div');
		var navtop = div[0].getElementsByTagName('div');
		var ul = navtop[1].getElementsByTagName('ul');
		var li = ul[0].getElementsByTagName('li');
		var username = li[4].firstChild.textContent;
		var highlight = false;
		if(GM_getValue('chartsRatedHighlighter', 1)) {
			if(GM_getValue('chartsOwnedHighlighter', 1)) {
				if(GM_getValue('chartsWishlistedHighlighter', 1)) highlight = 'rateownwishlist';
				else highlight = 'rateown';
			}
			else if(GM_getValue('chartsWishlistedHighlighter', 1)) highlight = 'ratewishlist';
			else highlight = 'have rated';
		}
		else if(GM_getValue('chartsOwnedHighlighter', 1)) {
			if(GM_getValue('chartsWishlistedHighlighter', 1)) highlight = 'wishlistown';
			else highlight = 'own';
		}
		else if(GM_getValue('chartsWishlistedHighlighter', 1)) highlight = 'have wishlisted';
		
		if(username!='log in / sign up' && highlight)
		{
			if(gUrlSubstr[3]=="list") var page = "list";
			else var page = "customchart";
			
			//single options set
			if(highlight == 'have rated') var urlRequest = 'http://rateyourmusic.com/collection_p/'+username+'/d.a,a,l,o,r0.5-5.0,n9999/';
			else if(highlight == 'own') var urlRequest = 'http://rateyourmusic.com/collection_p/'+username+'/d.a,a,l,o,r0.0-5.0,n9999,oo/';
			else if(highlight == 'have wishlisted') var urlRequest = 'http://rateyourmusic.com/collection_p/'+username+'/d.a,a,l,o,r0.0-5.0,n9999,ow/';
			
			if(urlRequest) {
				
				var records = highlightCells(urlRequest,highlight,page);
				appendTotal(highlight,records[0],records[1],records[2],page);				
			}
			else { //multiple options set
				
				if(highlight.match('rate')) { //rated
					var urlRequest = 'http://rateyourmusic.com/collection_p/'+username+'/d.a,a,l,o,r0.5-5.0,n9999/';
					var records = highlightCells(urlRequest,'have rated',page);
					appendTotal('have rated',records[0],records[1],records[2],page);
				}
				
				if(highlight.match('own')) { //owned
					var urlRequest = 'http://rateyourmusic.com/collection_p/'+username+'/d.a,a,l,o,r0.0-5.0,n9999,oo/';
					var records = highlightCells(urlRequest,'own',page);
					appendTotal('own',records[0],records[1],records[2],page);
				}
				
				if(highlight.match('wishlist')) { //wishlisted
					var urlRequest = 'http://rateyourmusic.com/collection_p/'+username+'/d.a,a,l,o,r0.0-5.0,n9999,ow/';
					var records = highlightCells(urlRequest,'have wishlisted',page);
					appendTotal('have wishlisted',records[0],records[1],records[2],page);
				}
			}
		}
	}
}

function highlightCells(urlRequest,highlight,page){
	var req = new XMLHttpRequest;
	var records=0; recordsIHave=0;
	req.open('GET', urlRequest, false);
	req.send(null);
	var response = req.responseText;
	var aux;
	if(page=="customchart") var xpathQuery = xpath('//table/tbody/tr/td/div/span[@style="font-size: x-large;"]');
	else var xpathQuery = xpath('//table/tbody/tr/td[@class="main_entry"]/h5');
	for(var i=0; i<xpathQuery.snapshotLength; i++) {
		var target = xpathQuery.snapshotItem(i);
		if(page=="customchart") var path = target.lastChild.pathname;
		else var path = target.firstChild.pathname;
		var href = 'href=\"';
		for(var e=0; e<path.length; e++) {href = href+"&#"+path.charCodeAt(e)+";";}
			aux = response.indexOf(href);
			if(aux!=-1) {
				
				recordsIHave++;
				if(page=="customchart") {
					var highlightEl = target.parentNode.parentNode.parentNode;
					var targetBG = highlightEl.style.backgroundColor;					
				}
				else {
					var highlightEl = target.parentNode.parentNode;
					var targetBG = highlightEl.style.backgroundColor;		
				}
				
				if(highlight == 'own') {
					if(targetBG=='rgb(204, 204, 255)') highlightEl.style.background="rgb(204, 255, 204)";
					else highlightEl.style.background="rgb(255, 255, 204)";
				}
				else if(highlight == 'have rated') {
					if(targetBG=='rgb(255, 255, 204)') highlightEl.style.background="rgb(204, 255, 204)";
					else highlightEl.style.background="rgb(204, 204, 255)";
				}
				else if(highlight == 'have wishlisted') {
					if(targetBG=='rgb(204, 204, 255)') highlightEl.style.background="rgb(255, 204, 255)";
					else highlightEl.style.background="rgb(255, 204, 204)";
				}
			}
		records++;
	}	
	var returnArray = new Array();
	returnArray[0] = records;
	returnArray[1] = recordsIHave;
	returnArray[2] = target;
	return returnArray; 
}

function appendTotal(havetext,records,recordsIHave,target,page) {
			var row = document.createElement('tr');
			if(page=="customchart") {
				for(var i=0; i<3; i++)
				{
					var cell = document.createElement('td');
					if(i==0) 		{cell.appendChild(document.createTextNode('You '+havetext));}
					else if(i==1)	{cell.appendChild(document.createTextNode(recordsIHave+'/'+records));}
					else 			{cell.appendChild(document.createTextNode('of these records'));}
					cell.style.fontSize = '20px !important';
					cell.style.fontWeight = 'bold';
					cell.style.color = '#777777';
					cell.style.backgroundColor = (havetext=='both') ? '#CCFFCC' : (havetext=='own') ? '#FFFFCC' : (havetext=='have rated') ? '#CCCCFF' : (havetext=='have wishlisted') ? '#FFCCCC' : '';
					cell.style.textAlign = (i!=2) ? 'center' : 'left';
					row.appendChild(cell);
				}
			}
			else {
				for(var i=0; i<2; i++) {
					var cell = document.createElement('td');
					if(i==0) 		{cell.appendChild(document.createTextNode('You '+havetext));}
					else 			{cell.appendChild(document.createTextNode(recordsIHave+'/'+records+' of these records'));}
					cell.style.fontSize = '20px !important';
					cell.style.fontWeight = 'bold';
					cell.style.color = '#777777';
					cell.style.backgroundColor = (havetext=='both') ? '#CCFFCC' : (havetext=='own') ? '#FFFFCC' : (havetext=='have rated') ? '#CCCCFF' : (havetext=='have wishlisted') ? '#FFCCCC' : '';
					cell.style.textAlign = (i!=1) ? 'center' : 'left';
					row.appendChild(cell);
				}
			}
			target.parentNode.parentNode.parentNode.parentNode.appendChild(row);
}

function xpath(query) /*Parses xPath queries*/
{
	return document.evaluate(query, document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
}