// ==UserScript==
// @name           Universal Picture Bubbles
// @namespace      www.daddy.sk
// @description    Shows larger version of pictures in tooltip bubble after pointing the mouse. Supports StumbleUpon, myspace, last.fm, facebook, imdb, flickr, youtube (sort of..)
// @include        *.youtube.com/*
// @include        http://youtube.com/*
// @include        http://stumbleupon.com/*
// @include        *.stumbleupon.com/*
// @include        *.last.fm/*
// @include        *.imdb.com/*
// @include        *.myspace.com/*
// @include        *.flickr.com/*
// @include        *.blogspot.com/*
// @include        *.photobucket.com/*
// @include        *.facebook.com/*
// @include        *.dealextreme.com/*
// ==/UserScript==

// Based on my Stumbleupon Avatar Bubbles script
// Still uses some parts of bubble Tooltips by Alessandro Fulciniti  
//		http://web-graphics.com/mtarchive/001717.php
//		http://web-graphics.com/mtarchive/BtJsCode.html

scriptName		= 'Universal Picture Bubbles';
versionURL		= "http://gm.daddy.sk/scripts/versions/universalpicturebubbles.txt";	// URL to file containing version number of the script stored on owners server.
sourceURL		= "http://gm.daddy.sk/scripts/universal_picture_bubble.user.js";		// URL to the source of the scripts latest version
homepageURL		= "http://gm.daddy.sk/"				// URL of the scripts homepage.
greaseMonkeyURL	= "http://www.greasespot.net/";
msgNodeXPath	= "//body"; 						// XPath to the element, in which the 'New script version' message should be displayed.
currentVersion	= 3;								// Version of the script contained in this file. ALWAYS update along with 
updateCheckFrequency 		= 0; 					// How many days should pass between two checks for updates. (0 means: check always)
checkForUpdatesByDefault	= true;
debugMode		= true;

TOOLTIP_CLASSNAME = 'UPBtooltip';

// ****************** User changeable ******************
// ******************        Settings        ******************
var S_OPACITY = "0.97";
// ****************** /User changeable *****************

var tinyPics, singleAvatar;

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;
}

function getURL(URL, fOnLoad, fOnError){
    GM_xmlhttpRequest({
        method: 'GET',
        url: URL,
        onload: fOnLoad,
		onerror: fOnError
		});
}

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;
}

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

// 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 = "New version of the <b><a href=\"" + homepageURL + "\" target=\"_blank\">" + scriptName + "</a></b> Greasemonkey Script was released. Click <a href=\"" + sourceURL + "\">here</a> to install it.";
					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('checkForUpdates', true);
	GM_setValue('lastVersionCheck', 0);
    document.location.reload();
}

function showTooltipPic(e){
	var content;
	if (e==null) {
		e = window.event;
	}
	// ****************** User changeable ******************
	// Content is defined here:
	var origImg, newImg, center, src, location, locationParts, text="", parent;
	origImg 			= e.target;
	parent				= origImg.parentNode;
	newImg				= document.createElement('img');
	center				= document.createElement('center');
	src					= origImg.src;	
	locationParts		= window.location.hostname.split('.');
	location			= (locationParts[locationParts.length - 2]+"."+locationParts[locationParts.length - 1]).toLowerCase();
	log('location: ' + location);
	log('title: ' + parent.title);	
	var pos;
	switch (location) {
		case "photobucket.com":
			src = src.replace("//th", "//i").replace("/th_", "/");
		case 'blogger.com':
		case 'blogspot.com':
			src = src.replace('/s200/', '/s1600-h/').replace('/s320/', '/s1600-R/');
			log(src);
		break;
		case 'imdb.com':			
			//var imgNamePrefix = '/VM._';
			var imgNamePrefix = '_V1._CR';
			var replaceWith = '_V1._SY400_SX600_.jpg';
			src = src.replace('/th-','/');
			if ((src.substring(src.length-8,src.length-7)=='/') && (src.substring(src.length-5)=='t.jpg')) {
				src = src.replace('t.jpg','m.jpg')
			}
			src = src.replace('_SX23_SY30_', '_SX100_SY140_').replace('_SY30_SX23_','_SX100_SY128_');
			pos = src.indexOf(imgNamePrefix);
			log(src.substring(pos + imgNamePrefix.length, pos + imgNamePrefix.length + 2));
			if ((pos>-1)) {//& (src.substring(pos + imgNamePrefix.length, pos + imgNamePrefix.length + 2) != 'SX') ) {
				src = src.substring(0, pos + imgNamePrefix.length) + replaceWith;
				log('Src: ' + src);
			}
		break;
		case 'stumbleupon.com':
			src = src.replace("mediumpics/", "mainpics/").replace("groupsupermini", "groupmini").replace("superminipics", "mediumpics").replace("iconpics", "mediumpics");
		break;
		case 'last.fm':
			src = src.replace("/serve/50/", "/serve/252/").replace("/serve/85/", "/serve/252/").replace("/serve/64s/", "/serve/252/").replace("/serve/126/", "/serve/252/").replace("/serve/34s/", "/serve/252/").
					replace("coverart/50x50/","coverart/130x130/").replace("/serve/64/", "/serve/252/").replace("/serve/126s/", "/serve/252/");
			if (origImg.title != "") {
				origImg.alt = origImg.alt + "\n" + origImg.title;
				origImg.title = "";
			}
			origImg.alt = origImg.alt.replace(String.fromCharCode(8211), "\n").replace(String.fromCharCode(10), "\n");
			parent.title = ' ';
			log("origImg.alt[11]: " + origImg.alt.charCodeAt(11) );
			log("origImg.alt: " + origImg.alt);
			log('text: ' + text);
		break;
		case 'myspace.com':
			src = src.replace("/s_","/m_").replace("_s.jpg","_m.jpg");
		break;
		case 'flickr.com':
			src = src.replace("_s.jpg", "_m.jpg");
		break;
		case 'facebook.com':
			if (src.indexOf("http://photos-") == -1) {
				src = src.replace("/q", "/n").replace("/t", "/n").replace("/s", "/n");
			} else {
				src = src.replace("/q", "/s").replace("/t", "/s");
			}
		break;
		case 'dealextreme.com':
			src = src.replace("_small.jpg", ".jpg").replace("_thumb.jpg", ".jpg");
		break;
	}
	newImg.setAttribute( "src", src ); 	
	newImg.setAttribute( "id", "tooltipImg" );
	center.appendChild(newImg);
	content = document.createElement('div');
	content.class = TOOLTIP_CLASSNAME;
	content.appendChild(center);
	
	// Replace parent title (if any) with text within tooltip by default.
	if (text == '') {
		if (parent.title != '' && parent.title != ' ') {
			text = parent.title;
			parent.title = ' ';
			origImg.alt = text;
		} else if (origImg.alt != '') {
			text = origImg.alt;
		}
	}
	if (text!='') {
		//content.appendChild(document.createElement('br'));
		var textDiv;
		textParts = text.split("\n");
		for (index in textParts) {
			textDiv = document.createElement('div');
			textDiv.class = "caption";
			textDiv.appendChild(document.createTextNode(textParts[index]))
			content.appendChild(textDiv);
		}
	}
	// ****************** /User changeable ******************
	
	// Tooltip generation
	var tooltip, btc;
	tooltip					= document.createElement("span");
	tooltip.className 		= TOOLTIP_CLASSNAME;
	tooltip.style.display 	= "block";
	tooltip.appendChild(content);
	tooltip.style.MozOpacity= S_OPACITY;
	btc = document.getElementById("btc");
	if (btc) {
		btc.appendChild(tooltip);
	} else {
		log('Error: btc not found');
	}
	log('tooltip: ' + tooltip.innerHTML);
}

function hideTooltipPic(e){
	var d=document.getElementById("btc");
	if (d.childNodes.length>0) {
		d.removeChild(d.firstChild);
	}
}

function locate(e) {
	var posX=0, posY=0;
	var scrollPosX=0,scrollPosY=0;
	var windowW, windowH;
	var tooltipW = 0, tooltipH = 0, btc;
	
	btc = document.getElementById("btc");
	if (!btc) {
		log('Error: btc not found');
	} 

	if (e==null) {
		e=window.event;
	}
	
	if (document.documentElement.scrollTop){
		scrollPosX = document.documentElement.scrollLeft;
		scrollPosY = document.documentElement.scrollTop;
		//log("document.documentElement.scrollTop");
	} else {
		scrollPosX = document.body.scrollLeft;
		scrollPosY = document.body.scrollTop;
		//log("!document.documentElement.scrollTop");
	}		

	windowW = window.innerWidth;
	windowH = window.innerHeight;
	//log('scrollPosX: ' + scrollPosX);
	//log('scrollPosY: ' + scrollPosY);
	posX = e.clientX + scrollPosX;
	posY = e.clientY + scrollPosY;
	
	// ****************** User changeable ******************
	// Get the tooltip width & height here
	var tooltipImg;
	
	tooltipImg = document.getElementById("tooltipImg");
	if (tooltipImg != null) {
		tooltipW = tooltipImg.width;
		tooltipH = tooltipImg.height;
	} else {
		log('tooltipImg not found');
	}
	// ****************** /User changeable ******************
	
	if (posX + tooltipW + 20 > windowW + scrollPosX) {
		posX = Math.max(document.documentElement.scrollTop?document.documentElement.scrollLeft:document.body.scrollLeft, posX - tooltipW - 35);
	} else if (posY + tooltipH + 20 > windowH + scrollPosY) {
		posY = Math.max(document.documentElement.scrollTop?document.documentElement.scrollTop:document.body.scrollTop, posY - tooltipH - 35);
	}
	//log('posX: ' + posX);
	//log('posY: ' + posY);
	//log('tooltipH: ' + tooltipH);
	//log('windowH: ' + windowH);
		
	btc.style.top		= (posY+10) + "px";
	btc.style.left		= (posX+10) + "px";
	btc.style.zIndex	= "99999";
	//log('btc.style.top:	' + btc.style.top);
	//log('btc.style.left:	' + btc.style.left);
	log('btc.innerHTML:	' + btc.innerHTML);
}

log(scriptName + ' started.');

// <Version check>
if (!checkGMVersion()) {
	return;
}

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; }"
)

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

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

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


// Create tooltip dummy
var dummy;
dummy		= document.createElement("span");
dummy.id	= "btc";
dummy.style.position = "absolute";
document.getElementsByTagName("body")[0].appendChild(dummy);

log('dummy.innerHTML:	' + dummy.innerHTML);

// ****************** User changeable ******************
// Define style
GM_addStyle(
	"." + TOOLTIP_CLASSNAME + "{ color:white; font:bold 11px/1.3 Arial,sans-serif; text-decoration:none;text-align:center; background-color: rgb(50,50,55); padding: 5px; border: 4px double black} " + 
	"." + TOOLTIP_CLASSNAME + " img{border: 2px groove white} " +
	"." + TOOLTIP_CLASSNAME + ".caption{border: 2px groove white; background-color: rgb(150,150,155)} "
	);

/*window.addEventListener(
	'load',
	function() {
		setTimeout(
			function () {*/
				// Get elements to be tooltiped 
				tinyPics = xPath("//img[" + 
						"contains(@src, 'superminipics/') or contains(@src, 'mediumpics/') " +
						"or contains(@src, '/serve/50/') or contains(@src, '/serve/85/') or contains(@src, '/serve/160/') or contains(@src, '/serve/130x130/') or contains(@src, '/serve/64s/') or contains(@src, '/serve/126/') or contains(@src, '/serve/34s/') or contains(@src, '/coverart/50x50/') or contains(@src, '/serve/64/' ) or contains(@src, '/serve/126s/') " +
						"or contains(@src, '/shops/assets/sleeveart/' ) " + 
						"or contains(@src, '/coverart/130x130/') or contains(@src, '/images/P/') " + 
						"or contains(@src, '/default.jpg' ) or contains(@src, '/th-') " + 
						"or ((contains(@src, 't.jpg') or contains(@src, '_SX23_SY30_') or contains(@src, 'SS90_.jpg') or contains(@src, 'SS80_.jpg') or contains(@src, 'SS100_.jpg') or contains(@src, 'SY30_SX23_.jpg')) and contains(@src, 'imdb.com')) " + 
						"or (contains(@src, 'images.myspacecdn.com/')) " +
						"or (contains(@src, '_s.jpg')) " +
						"or (contains(@src, '/s200/')) or (contains(@src, '/s320/')) " +
						"or (contains(@src, 'photobucket.com') and contains(@src, 'th')) " + //  and starts-with(@src, 'http://th')
						"or (contains(@src, '.facebook.com/profile')) " + // and (contains(@src, '/q') or contains(@src, '/t')))" +
						"or (contains(@src, 'http://profile.ak.facebook.com') and (contains(@src, '/q') or contains(@src, '/t') or contains(@src, '/s'))) " +
						"or (contains(@src, 'http://photos-') and (contains(@src, '/q') or contains(@src, '/t'))) " + // or contains(@src, '/s')
						"or (contains(@src, '/productimages/sku_'))" +
								"]");
// ****************** /User changeable ******************

				log('Pictures found: ' + tinyPics.length)

				for (i in tinyPics) {
					singleAvatar = tinyPics[i];
					//log('singleAvatar.src:	' + singleAvatar.src);
					singleAvatar.addEventListener("mouseover", showTooltipPic, true);
					singleAvatar.addEventListener("mouseout", hideTooltipPic, true);
					singleAvatar.addEventListener("mousemove", locate, true);
				}				
/*			},
		1000);
	},
  false
);*/

