// ==UserScript==
// @name Shackmarks
// @namespace http://www.socksandthecity.net/shackmarks
// @description Adds ability to bookmark Shack posts
// @include http://shacknews.com/*
// @include http://*.shacknews.com/*
// @exclude http://bananas.shacknews.com/*
// @exclude http://*.gmodules.com/*
// ==/UserScript==
/*
	------------------------------------------------------------

	Shackmarks
	http://socksandthecity.net/shackmarks
	Author: erotic sock
	Based heavily on shack[lol] scripted developed by Thom Wetzel

	------------------------------------------------------------

	Okay fellas, here's the shackmark script. This is pretty heavily
	based on ThomW's shack[lol] script so full credit goes to him for
	the javascript knowhow.
	
	Be sure to visit Thom's site for his neato stuff: http://www.lmnopc.com

	Cheers guys. Shoot me a shackmessage if you have any queries.
*/

(function() {

	var myDomain = 'socksandthecity.net';
	var version = 20081104; // obama victory edition

	// grab start time of script
	var benchmarkTimer = null;
	var scriptStartTime = getTime();
	
	// add some styles for the stars. keeps file size down as they're used a couple of times. thanks Thom!
	GM_addStyle(<><![CDATA[
	.shackStar { display: inline; float: none; padding:8px 8px 0px 8px;cursor: pointer; margin:0px 0px 0px 10px; border:none;}
	.shackColourStar { background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAIwSURBVDjLlZLNS5RRFMafe9/3vjPOjI1jaKKEVH40tGgRBWEibfoPQoKkVdtoEQQF4T/QqkVtWrSTFrVsF1FgJbWpIAh1k2PNh+PrfL4f95zTQk0HHKkDD/cc7vP8uHCuEhF0q/KnmXNgGR248PZFN4/GISXMC8L89DBPV0Dp4/SsazJjrtfb9/vdxfn/BgjzY5M8Aq8nBya+V3h93vtnQHFxat4kszntJAAAxus1YvnZQV5V/jyTEZarwnwFLGeFZdT0ZFOJdD84qoCDOpQ7grZfRNj020JSEOKvwvxGiF+q0tL0N5PuO+Mk0nC0B0BDsYCCImyzAIktBBloMwKJLSgKYcMAcdhC2KpVlIig+H5qxcv0n0xmj4Gbq+BwC2wtJLbgHUlMEFJwUpMIGpto16u+kJzSACAk+WCzvNbe+AVljkOYIcQQou3TbvdOJo+g4aNdqzaF+PT43HJVA8DQpcVIiPPtaqlEUQzlDELsTpgYwgTAQIjQqlUCtpQfn1spdmxh+PJSQyw9CrbKgM7tvcISQAxlBhC3GuCYXk3cWP25m3M7dk88qbWBRDVApaATOSjPBdXXwYEP5QyCgvjE/kwHgInHtHYBnYA2owhrPiiuw0sOw3EZFEagIB7qChDiYaUcNIoFtP1KxCTPhWiDw7WbXk9vKpnOgsI4exjg6Mbq96YQPxm79uPOvqvbXx4O3KrF6w8osv2df17kr5YXJq7vnw/S0v3k7Ie7xtud/wAaRnP+Cw8iKQAAAABJRU5ErkJggg%3D%3D)  0px 6px no-repeat;}
	.shackGreyStar { background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAADHWlDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAChTY2BgnuDo4uTKJMDAUFBUUuQe5BgZERmlwH6egY2BmYGBgYGBITG5uMAxIMCHgYGBIS8/LxUiCgeMDAzfrjEwMjAwMFzWdXRxckWTJwRYkwuKShgYGA4wMDAYpaQWJzMwMHxhYGBILy8pKGFgYIxhYGAQScouKGFgYCxgYGAQyQ4JcmZgYGxhYGDiKUmtKGFgYGBwzi+oLMpMzyhRMLS0tFRwTMlPSlUIriwuSc0tVvDMS84vKsgvSixJTWFgYIDawcDAwMDrkl+i4J6YmadgZKAKFaMaiIiMUoCwEOGDEEOA5NKiMgiLkYGBgUGAQYHBgMGBIYAhkaGeYQHDUYY3jOKMLoyljCsY7zGJMQUxTWC6wCzMHMm8kPkNiyVLB8stVj3WVtZ7bJZs09i+sYez7+ZQ4uji+MKZyHmBy5FrC7cm9wIeKZ6pvEK8k/iE+abxy/AvFtAR2CHoKnhFKFXoh3CviIrIXtFw0S9ik8SNxK9IVEjKSR6TypeWlj4hUyarLntLrk/eRf6PwlbFQiU9pbfKa1UKVE1Uf6odVO/SCNVU0vygdUB7kk6qrpWeoN4r/SMGCwxrjWKMbU3kTZlNX5pdMN9pscRyglWdda5NnG2gnau9tYOxo46TmrOSi4KrvJuCu7KHuqeul4m3jY+7b7Bfgn9+QH3gxKClwbtCLoa+DGeKkIu0ioqIroiZGbsn7kECW6JuUlhyQ8qa1JvpHBkWmZlZc7Mv5rLn2edXFGwqfFesXZJVuqrsTYV+ZUnVrhrGWq+6qfUPG/WaaprPtsq1FbYf7ZTuKuo+3ava19h/d6LNpNmT/06Nn3Z4hsbM/lnf5yTMPT3ffMHSRSKLW5d8W5a5/N7KkFWn17is3bfecsO2TSabt2w12bZ9h9XO/btd95zdF7b/wcGcQz+PtB8TP77ipPWpc2eSz/46P+mi9qWjVxKv/rs+56bNrbt36u8p3z/xMO+x2JP9zzJfiLw8+Dr/rfy7Cx+aPpl+fvV1wffwnwK/Tv1p/ef4/z8ADQAPNDgFuWoAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAAAlwSFlzAAALEwAACxMBAJqcGAAAATlJREFUKFN9z71LAnEcx/Hf5NTU0uRf0X/S4tLSP+AYBAVCQRANQkPiQwZHXel5Zz5cV3d6emn2oCVoQkhDNEQUuahRQ++GEjyo+Czfh9fw/QrEeErT9ox74moQxW6h9w8o+qpUMAJ/Auu1QYP8R9bzKzADFZpcYaHJY+Bkojxny4WOOajS5AKHGjqJodzdUSX/tlfY7Uta3NChTZ0yJhZlLHQ09og9C4R1d8YtDWo4FDHIkSaFToJoLzwpEEeew4cKLaqUMNE5IIVBgmg/PPVzZG4i81SnhoVBFpUUOpG3kHfsC3WxwDnH5EmjkEFhU3W9mZRsKphYmGgkUQheu8B+zeGUEhkUdLIorD26wO69g8bWe0QKBTcGEWRWhi4g9eP92Pp3jVj1L78sfbpAfHa0HGXBN+9BIL4AOwFN2K/8CNIAAAAASUVORK5CYII%3D) 0px 6px no-repeat;}
	]]></>);

	function getTime() { benchmarkTimer = new Date(); return benchmarkTimer.getTime(); }

	function stripHtml(html)
	{
		return String(html).replace(/(<([^>]+)>)/ig, '');
	}
	
	function removeClassName(needle, haystack)
	{
		var straws = haystack.split(' ');
		var idx = straws.indexOf(needle)
		if (idx == -1)
		{
			 return haystack;
		}
		straws.splice(idx, 1);
		return straws.join(' ');
	}

	function findUsername()
	{
		var n = getElementByClassName(document.getElementById('masthead'), 'a', 'username');
		if(n)
		{
			return stripHtml(n.innerHTML);
		}
		else return false;
	}

	// ThomW: I took getElementsByClassName and stripped it down to just what's needed by this script
	function getElementByClassName(oElm, strTagName, strClassName)
	{
		var arrElements = oElm.getElementsByTagName(strTagName);
		for(var i=0; i < arrElements.length; i++)
		{
			if (arrElements[i].className.indexOf(strClassName) == 0)
			{
				return arrElements[i];
			}
		}
	}

	// shackmark functions
	function installShackmarksButton(threadIdList)
	{
		var dbg = false;

		var startTime = getTime();

		var msg = '';

		// this makes the script run on the right document when called from the iframe
		if (unsafeWindow != unsafeWindow.top)
		{
			doc = unsafeWindow.top.document;
		}
		else
		{
			doc = document;
		}

		threadIdList = String(threadIdList).split(',');
		var numThreads = threadIdList.length;

		for (var i = 0; i < numThreads; i++)
		{
			var threadId = threadIdList[i];

			// find threadId
			var t = doc.getElementById('item_' + threadId);
			if (!t)
			{
				if (dbg) { GM_log('COULD NOT FIND root_' + threadId); }
				return false;
			}

			// find div.postmeta
			var pm = getElementByClassName(t, 'span', 'author');
			if (!pm)
			{
				if (dbg) { GM_log('getElementsByClassName could not locate span.author'); }
				return false;
			}

			var d = doc.createElement('div');
			//d.setAttribute('style', 'display: inline; float: none; padding-left: 10px;cursor: pointer; border:none;height:16px; width:16px;');
			//d.src=getGreyStar();

			d.setAttribute('id','shackmark' + threadId);
			d.setAttribute('onClick','shackmarkThread(event)');
			d.className = 'shackStar shackGreyStar';
			// add d to pm
			pm.appendChild(d);
		}
	}

	function unshackmarkThread2(thread) // used on the profile page to remove a shackmark.
	{
		// find the user
		var userName = findUsername();
		
		var person ='';
		var arr = String(location.href).split('/');
		
		if (arr.length == 5) // i stole this from thom
		{
			person = decodePerson(arr[4]);
		}
		
		if (!userName)
		{
			unsafeWindow.alert('You have to be logged in to Shacknews to unshackmark a post');
			return;
		}
		else if (userName == person) // make sure it's the correct user deleting items
		{
			// assemble the url
			var addr = 'http://' + myDomain + '/shackmarks/unshackmark.php?user=' + encodeURI(userName) + '&id=' + thread + '&version=' + version;
	
			GM_log(addr);
	
			// use xmlhttpRequest to post the data
		  	GM_xmlhttpRequest({ method:"GET",
  					url: addr,
				    onload:function(result)
				    {
				     	try
				     	{
				     		if (result.responseText.substr(0, 3) != 'ok ') // make sure the post was unshackmarked
				     		{
				     			if (String(result.responseText).length)
				     			{
				     				GM_log(result.responseText);
				     				unsafeWindow.alert(result.responseText);
				     			}
				     			else
				     			{
				     				unsafeWindow.alert('Couldn\'t remove shackmark.');
				     			}
				     		}
				     		else
			     			{
								// remove the table row
								var objShackmarkTable = document.getElementById('shackmarks');
								var objShackmarkTbody = objShackmarkTable.getElementsByTagName('tbody')[0];
								var objShackmark = document.getElementById('shackmark' + result.responseText.substr(3));
			     				objShackmarkTbody.removeChild(objShackmark);
				     		}
				      }
				      catch (e)
				      {
				      	unsafeWindow.alert('Couldn\'t remove shackmark.');
				      }
				    }
		  		});
		}
		else
		{
			unsafeWindow.alert('You can\'t delete someone else\'s shackmarks!');
			return;
		}
	}

	function shackmarkThread2(thread)
	{
		var userName;

		// find the user
		var userName = findUsername();
		if (!userName)
		{
			unsafeWindow.alert('You have to be logged in to Shacknews to shackmark a post');
			return;
		}

		//
		var addr = 'http://' + myDomain + '/shackmarks/shackmark.php?user=' + encodeURI(userName) + '&id=' + thread + '&version=' + version;

		GM_log(addr);

		// use xmlhttpRequest to post the data
	  	GM_xmlhttpRequest({ method:"GET",
	  			url: addr,
			    onload:function(result)
			    {
			     	try
			     	{
						// if the first 2 letters aren't "ok" then we have a problem
			     		if (result.responseText.substr(0, 2) != 'ok')
			     		{
			     			if (String(result.responseText).length)
			     			{
			     				GM_log(result.responseText);
								//unsafeWindow.alert(result.responseText);
			     			}
			     			else
			     			{
			     				unsafeWindow.alert("Your shackmark may have failed.  Sorry.  :(");
			     			}
			     		}
			     		else
		     			{
		     				var objShackmark = document.getElementById('shackmark' + result.responseText.substr(4));
							var starText = doc.createElement('span');

							switch(result.responseText.substr(2, 1))
							{
								case '1': // shackmark successfully added
									starText.innerHTML='shackmarked';
									break;
								case '2': // shackmark already exists
									starText.innerHTML='already shackmarked';
									break;
								default: // this shouldn't occur.
									starText.innerHTML='';
									break;
							}

							starText.setAttribute('style','color:white;margin-left:10px;font-weight:bold;');

							objShackmark.className='shackStar shackColourStar'; // change star graphic
							objShackmark.setAttribute('onClick',''); // remove clickability
							objShackmark.style.cursor="default"; // change cursor back to default
							objShackmark.parentNode.appendChild(starText); // add text to post header

                        }
			      }
			      catch (e)
			      {
			      	unsafeWindow.alert('Shackmark failed.');
			      }
			    }
	  		});
	}

	function decodePerson(person)
	{
		person = decodeURI(person);
		person = person.replace(/#/,'');
		person = person.replace(/\+/,' ');
		return person;
	}

	function showShackmarks2() // used on profile page to show shackmark listing
	{
		var userName = findUsername();
		var addr = '';
		var person ='';
		var arr = String(location.href).split('/');
		
		if (arr.length == 5)
		{
			person = decodePerson(arr[4]);
			//person = decodeURI(arr[4]);
			//person = person.replace(/#/,'');
			//person = person.replace(/\+/,' ');
		}

		if (person.length)
		{
			addr = 'http://' + myDomain + '/shackmarks/list.php?user=' + encodeURI(person) + '&version=' + version;

			if (userName == person) // if the person is looking at their own profile page, show the links
			{
				addr = addr+'&showDelete=1';
			}
			
			GM_log(addr);
	
			// there has to be a neater way to do this. will also change as the shack sorts out its game library feature.
			// we're trying to get all the various divs to delete, but they're all classes and not ids. boo.
			var profile = document.getElementById('profile');
			var sectionContainer = getElementByClassName(profile,'div','sectioncontainer');
			var sectionProfile = getElementByClassName(sectionContainer,'div','profilesection');
			var br = document.createElement('br');
			var tableShackmarks = document.createElement('div');
			tableShackmarks.style.marginbottom = '5px';
			tableShackmarks.style.width = '100%';
			
			//profileContact.paddingbottom = '50px';
	
			GM_xmlhttpRequest({ method:"GET",
	  			url: addr,
			    onload:function(result)
			    {
			     	try
			     	{
			     		if (result.responseText.substr(0, 3) != 'ok ')
			     		{
			     			if (String(result.responseText).length)
			     			{
			     				GM_log(result.responseText);
			     				tableShackmarks.innerHTML = result.responseText;
			     			}
			     			else
			     			{
			     				tableShackmarks.innerHTML = '<p>Couldn\'t retrieve shackmarks.</p>';
			     			}
			     		}
			     		else
		     			{
		     				tableShackmarks.innerHTML = result.responseText.substr(3);
			     		}
			      }
			      catch (e)
			      {
			      	tableShackmarks.innerHTML = '<p>Couldn\'t retrieve shackmarks.</p>';
			      }
			    }
	  		});
			
			getElementByClassName(profile,'a','active').className='';
			document.getElementById('shackmarkButton').getElementsByTagName('a')[0].className='active';
			sectionContainer.removeChild(sectionProfile);
			sectionContainer.appendChild(tableShackmarks);
		}
	}


	/* MAIN
	*/

	// Since this is used by several cases I'm going to add this to every page, even where it's not needed.
	if (!unsafeWindow.shackmarkThread)
	{
		unsafeWindow.shackmarkThread = function(event)
		{
			//alert('clicked');
			var threadId = event.target.getAttribute('id').substr(9);
			window.setTimeout(function()
					{
						shackmarkThread2(threadId);
					}, 1);
		}
	}

	//
	// PROFILE PAGE
	//
	if ((String(location.href).indexOf('profile/') != -1) ||
			(String(location.href).indexOf('shacknews.com/profile/') != -1) ||
			(String(location.href).indexOf('shacknews.com/library/') != -1) ||
			(String(location.href).indexOf('shacknews.com/librarywanted/') != -1))
	{

		var userName = findUsername();

		//if (String(location.href).indexOf('profile/'+encodeURI(userName)) != -1 || String(location.href).indexOf('profile/'+userName.replace(/ /, '+')) != -1)
		//{
			// create the link
			var smLink = document.createElement('li');
			smLink.innerHTML = '<a href="#">Shackmarks</a>'; //<div class="shackColourStar" style="background-position:5px 1px;"></div>
			smLink.setAttribute('onClick', 'showShackmarks()');
			smLink.setAttribute('id', 'shackmarkButton');			
			var profileblock = getElementByClassName(document,'div','profileblock profiletabs tabs');
			var ul = profileblock.getElementsByTagName('ul')[0];
			ul.appendChild(smLink);
		//}

		
		if (!unsafeWindow.showShackmarks)
		{
			unsafeWindow.showShackmarks = function(threadId)
			{
				//alert('clicked');
				//var threadId = event.target.getAttribute('id').substr(9);
				window.setTimeout(function()
						{
							showShackmarks2();
						}, 1);
			}
		}
		if (!unsafeWindow.unshackmarkThread)
		{
			unsafeWindow.unshackmarkThread = function(threadId)
			{
				//alert('clicked');
				//var threadId = event.target.getAttribute('id').substr(9);
				window.setTimeout(function()
						{
							unshackmarkThread2(threadId);
						}, 1);
			}
		}
	}

	//
	// IFRAME CALLS
	//
	else if (String(location.href).indexOf('frame_laryn.x') != -1)
	{
		// override standard show_item_fullpost with one that supports this script
		if (!unsafeWindow.shackmark_show_item_fullpost)
		{
			unsafeWindow.shackmark_show_item_fullpost = unsafeWindow.show_item_fullpost;
			unsafeWindow.show_item_fullpost = function(root_id, article_id, fullpost_element)
			{
				// call original function
				unsafeWindow.shackmark_show_item_fullpost(root_id, article_id, fullpost_element);

				// install shackmark button in updated parent window
				installShackmarksButton(article_id);
			}
		}

		// override function used for Refresh Thread button
		if (!unsafeWindow.shackmark_replace_whole_element_from_iframe)
		{
			unsafeWindow.shackmark_replace_whole_element_from_iframe = unsafeWindow.replace_whole_element_from_iframe;
			unsafeWindow.replace_whole_element_from_iframe = function(id)
			{
				// call the original function
				unsafeWindow.shackmark_replace_whole_element_from_iframe(id);

				// find all the fullposts and add lol buttons
				var items = document.evaluate("//div[contains(@class, 'fullpost')]/..", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
				for (item = null, i = 0; item = items.snapshotItem(i); i++)
				{
					var threadId = item.id.substr(5);
					installShackmarksButton(threadId);
				}
			}
		}
	}

	//
	// LARYN.X
	//
	else if (String(location.href).indexOf('laryn.x') != -1)
	{
		if (!unsafeWindow.shackmark_show_item_fullpost)
		{
			// override standard show_item_fullpost with one that supports this script
			unsafeWindow.shackmark_show_item_fullpost = unsafeWindow.show_item_fullpost;
			unsafeWindow.show_item_fullpost = function(root_id, article_id, fullpost_element)
			{
				// call original function
				unsafeWindow.shackmark_show_item_fullpost(root_id, article_id, fullpost_element);

				installShackmarksButton(article_id);
			}
		}

		// find all the fullposts on the page
		var items = document.evaluate("//div[contains(@class, 'fullpost')]/..", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
		var idList = '';
		for (item = null, i = 0; item = items.snapshotItem(i); i++)
		{
			idList += idList.length ? ',' : '';
			idList += item.id.substr(5);
		}
		installShackmarksButton(idList);

	}

	// log execution time
	GM_log(location.href + ' / ' + (getTime() - scriptStartTime) + 'ms');

})();
