// ==UserScript==
// @name		HaBCoDisp
// @namespace	http://www.kanasansoft.com/
// @description display hatena bookmark's comments (need USWManager)
// @include		*
// ==/UserScript==

(function(){

	var DEBUG_FLAG			=	true;

	var NAMESPACE_DEFAULT	=	"http://purl.org/rss/1.0/"						;
	var NAMESPACE_RDF		=	"http://www.w3.org/1999/02/22-rdf-syntax-ns#"	;
	var NAMESPACE_DC		=	"http://purl.org/dc/elements/1.1/"				;
	var NAMESPACE_TAXO		=	"http://purl.org/rss/1.0/modules/taxonomy/"		;

	var XPATH_RDF			=	"*[local-name()='RDF' and namespace-uri()='"+NAMESPACE_RDF+"']"					;
	var XPATH_ITEM			=	"*[local-name()='item' and namespace-uri()='"+NAMESPACE_DEFAULT+"']"			;
	var XPATH_TITLE			=	"*[local-name()='title' and namespace-uri()='"+NAMESPACE_DEFAULT+"']"			;
	var XPATH_LINK			=	"*[local-name()='link' and namespace-uri()='"+NAMESPACE_DEFAULT+"']"			;
	var XPATH_DESCRIPTION	=	"*[local-name()='description' and namespace-uri()='"+NAMESPACE_DEFAULT+"']"		;
	var XPATH_DATE			=	"*[local-name()='date' and namespace-uri()='"+NAMESPACE_DC+"']"					;
	var XPATH_SUBJECT		=	"*[local-name()='subject' and namespace-uri()='"+NAMESPACE_DC+"']"				;

	var ICON_URI_UNLOAD		=	"data:image/gif;base64,"											+
								"R0lGODdhEAAQAMICAP8AACpfyVJ554Wl%2Bv%2F%2FAP%2F%2F%2F1J551J55ywA"	+
								"AAAAEAAQAAADRzi63DKlCBFnrCJASTmO2ueN4SVipTWqaaeymwXMwDVp00TTeTbk"	+
								"s17w9tMBekicEdlTCoZGgtT53B2lBGp1iA1kAuCwWJwAADs%3D"				;
	var ICON_URI_ERROR		=	"data:image/gif;base64,"											+
								"R0lGODdhEAAQAMICAP8AACpfyVJ554Wl%2Bv%2F%2FAP%2F%2F%2F1J551J55ywA"	+
								"AAAAEAAQAAADRji63DKlCBFnrCJASTmO2ueN4SVipTWqaaeymwXMwDVp00TTeTbk"	+
								"s17w9tMBekicEdlTCoZGmvO5O0qLQB4VEMgEvuBwOAEAOw%3D%3D"				;
	var ICON_URI_LOADED		=	"data:image/gif;base64,"											+
								"R0lGODdhEAAQAMICAP8AACpfyVJ554Wl%2Bv%2F%2F%2F1J551J551J55ywAAAAA"	+
								"EAAQAAADQzi63DKECBFnrCJASTmO2ueN4SVipTWqaaeymwXMwDVp00TTeTbks17w"	+
								"9tMBekicEdlTCoZLonB3zDmN0FsmwO16vQkAOw%3D%3D"						;
	var ICON_URI_LOADING	=	"data:image/gif;base64,"											+
								"R0lGODlhEAAQAOMEAAAAAP8AACpfyWZmAFJ554Wl%2Bv%2F%2FAP%2F%2F%2F1J5"	+
								"51J551J551J551J551J551J551J55yH%2FC05FVFNDQVBFMi4wAwEAAAAh%2BQQB"	+
								"BQAIACwAAAAAEAAQAAAETLDISSsp5xCSd%2B6EgGkcCWbiaa7pp4Ktt8pxKdOjF%"	+
								"2BzBt4mbDY8XDBWCu2LydxQGilCgE1qUEpZOA2BgvQ6fmkPXuxwADIKQYM1utyMA"	+
								"IfkEAQUADwAsAAAAABAAEAAABE2wyEkrKecQknfuhIBpHAlm4mmu6aeCrbfKcSnT"	+
								"oxfswbeJmw2PFwwVgrti8ncUBopQoBNalBKWzoMBYL0OnwPCoOtdAgwHQUjAbrvd"	+
								"EQAh%2BQQBBQAPACwAAAAAEAAQAAAETbDISSsp5xCSd%2B6EgGkcCWbiaa7pp4Kt"	+
								"t8pxKdOjF%2BzBt4mbDY8XDBWCu2LydxQGilCgE1qUEpbOwcFgvQ6fAAKg610aDg"	+
								"NBSMBuu90RACH5BAEFAA8ALAAAAAAQABAAAARNsMhJKynnEJJ37oSAaRwJZuJpru"	+
								"mngq23ynEp06MX7MG3iZsNjxcMFYK7YvJ3FAaKUKATWpQSlk7A4GC9Dp8GgqHrXR"	+
								"4GAEFIwG673REAOw%3D%3D"											;
	var ICON_URI_CHECK_OFF	=	"data:image/gif;base64,"											+
								"R0lGODlhDAAMAKEBAAAAAMzMzMzMzMzMzCH5BAEKAAIALAAAAAAMAAwAAAIclI%2"	+
								"BpCe2NQJgURFovDvbI3RkfFgpj5j3OwrZGAQA7"							;
	var ICON_URI_CHECK_ON	=	"data:image/gif;base64,"											+
								"R0lGODlhDAAMAKECAAAAAGZmZszMzMzMzCH5BAEKAAMALAAAAAAMAAwAAAIjnI%2"	+
								"BJAQkPGQJBCCbaefXlyYTflnmjAVyUpaHWew7Q3Cr2bRQAOw%3D%3D"			;
	var ICON_URI_RELOAD		=	"data:image/gif;base64,"											+
								"R0lGODlhDAAMAKEBAAAAAMzMzMzMzMzMzCH5BAEKAAIALAAAAAAMAAwAAAIglI8p"	+
								"waELInAozDaPpWb33HkQtYFiyXnWVV0S2IXMoxQAOw%3D%3D"					;

	var ICON_URI_WIDGET		=	"data:image/gif;base64,"											+
								"R0lGODdhEAAQAMIGADMzM2ZmZpmZmcTEzsrKzMzMzP%2F%2F%2F%2F%2F%2F%2Fy"	+
								"wAAAAAEAAQAAADQ1i63CowSgnKnCXAemXIAtdlnyVezgkpJaMK7UAsJ7jIAaBba5"	+
								"MDgRwPxsgFgxxQC3gUEovMo6hViEqHyyZSx%2B16dQkAOw%3D%3D"				;


	var DisplayHatenaBookmarkComments
		=	function(){
			this.makeDisplayArea();
			this.dockIcon.setAttribute("src",ICON_URI_UNLOAD);
			setInnerText(this.message,"unload");
			this.displayAutoload();
			if(GM_getValue("autoload")){
				this.getComments();
			}
		}

	DisplayHatenaBookmarkComments.prototype.getClosurizeMethod
		=	function(methodName){
			var _this		=	this;
			var _methodName	=	methodName;
			return function(){
				_this[_methodName].apply(_this,arguments);
			}
		}

	DisplayHatenaBookmarkComments.prototype.makeDisplayArea
		=	function(){

			var dockIcon		=	document.createElement("img");
			var mainArea		=	document.createElement("div");
			var message			=	document.createElement("div");
			var comments		=	document.createElement("div");
			var control			=	document.createElement("div");
			var autoload		=	document.createElement("span");
			var autoloadIcon	=	document.createElement("img");
			var autoloadText	=	document.createElement("span");
			var reload			=	document.createElement("span");
			var reloadIcon		=	document.createElement("img");
			var reloadText		=	document.createElement("span");

			setInnerText(autoloadText,"auto load");
			setInnerText(reloadText,"reload");

			reloadIcon.setAttribute("src", ICON_URI_RELOAD);
			mainArea.setAttribute("style","color:#000000;background-color:#ffffff;font-size:9px;text-align:left;border:outset 2px #999999;opacity:0.5");
			comments.setAttribute("style","margin:0px;padding:0px;width:200px;height:200px;overflow:auto;border:inset 2px #999999;");
			autoload.setAttribute("style","cursor:pointer");
			reload.setAttribute("style","cursor:pointer");

			mainArea.addEventListener(
				"mouseout",
				(function(mainArea){
					var _mainArea=mainArea;
					return function(){
						_mainArea.style.opacity="0.5";
					}
				})(mainArea),
				true
			);
			mainArea.addEventListener(
				"mouseover",
				(function(mainArea){
					var _mainArea=mainArea;
					return function(){
						_mainArea.style.opacity="0.9";
					}
				})(mainArea),
				true
			);
			autoload.addEventListener("click",this.getClosurizeMethod("toggleAutoload"),true);
			reload.addEventListener("click",this.getClosurizeMethod("getComments"),true);

			mainArea.appendChild(message);
			mainArea.appendChild(comments);
			mainArea.appendChild(control);
			control.appendChild(autoload);
			control.appendChild(reload);
			autoload.appendChild(autoloadIcon);
			autoload.appendChild(autoloadText);
			reload.appendChild(reloadIcon);
			reload.appendChild(reloadText);

			this.dockIcon		=	dockIcon;
			this.mainArea		=	mainArea;
			this.message		=	message;
			this.comments		=	comments;
			this.autoloadIcon	=	autoloadIcon;

		}

	DisplayHatenaBookmarkComments.prototype.toggleAutoload
		=	function(){
			GM_setValue("autoload",!GM_getValue("autoload"));
			this.displayAutoload();
		}

	DisplayHatenaBookmarkComments.prototype.displayAutoload
		=	function(){
			this.autoloadIcon.setAttribute("src",GM_getValue("autoload")?ICON_URI_CHECK_ON:ICON_URI_CHECK_OFF);
		}

	DisplayHatenaBookmarkComments.prototype.getComments
		=	function(){
			debugLog("getComments");
			this.dockIcon.setAttribute("src",ICON_URI_LOADING);
			setInnerText(this.message,"loading");
			var opt={
				method	:	"get"														,
				url		:	"http://b.hatena.ne.jp/entry/rss/"+escape(location.href)	,
				onload	:	this.getClosurizeMethod("getCommentsLoadCallback")			,
				onerror	:	this.getClosurizeMethod("getCommentsErrorCallback")
			}
			debugLog("getComments");
			GM_xmlhttpRequest(opt);
			debugLog("getComments");
		}

	DisplayHatenaBookmarkComments.prototype.getCommentsErrorCallback
		=	function(responseDetails){
			this.dockIcon("src",ICON_URI_ERROR);
			setInnerText(this.message,"error");
		}

	DisplayHatenaBookmarkComments.prototype.getCommentsLoadCallback
		=	function(responseDetails){
			debugLog("getCommentsLoadCallback");
			var parser		=	new DOMParser();
			var dom			=	this.parseDomFromString(responseDetails.responseText);
			var comments	=	this.getCommentsFromDom(dom);
			this.displayComments(comments);
			this.dockIcon.setAttribute("src",ICON_URI_LOADED);
			setInnerText(this.message,"loaded "+comments.length+" users");
		}

	DisplayHatenaBookmarkComments.prototype.parseDomFromString
		=	function(str){
			var parser		=	new DOMParser();
			var dom			=	parser.parseFromString(str,"text/xml");
			return dom;
		}

	DisplayHatenaBookmarkComments.prototype.getCommentsFromDom
		=	function(dom){
			var items		=	getElementsByXPath(dom,"/"+XPATH_RDF+"[1]/"+XPATH_ITEM);
			var lines		=	map(items,this.getCommentDetailFromDom);
			return lines;
		}

	DisplayHatenaBookmarkComments.prototype.getCommentDetailFromDom
		=	function(dom){
			var	commentDetail={
					titles			:	map(getElementsByXPath(dom,XPATH_TITLE),getInnerText)		,
					links			:	map(getElementsByXPath(dom,XPATH_LINK),getInnerText)		,
					descriptions	:	map(getElementsByXPath(dom,XPATH_DESCRIPTION),getInnerText)	,
					dates			:	map(getElementsByXPath(dom,XPATH_DATE),getInnerText)		,
					subjects		:	map(getElementsByXPath(dom,XPATH_SUBJECT),getInnerText)
				}
			return commentDetail;
		}

	DisplayHatenaBookmarkComments.prototype.displayComments
		=	function(comments){
			var commentElements	=	map(comments,this.formatComment);

			while(this.comments.firstChild){
				this.comments.removeChild(this.comments.firstChild);
			}

			map(commentElements,(function(_this){return function(comment){_this.comments.appendChild(comment);}})(this));

	}
	DisplayHatenaBookmarkComments.prototype.formatComment
		=	function(comment){

			var formatDefault
				=	function(ary){
					return ary.length==0?"":ary[0];
				}
			var formatTitles=formatLinks=formatDescriptions=formatDefault;
			var formatDates
				=	function(ary){
					var date			=	formatDefault(ary);
					var dateWithFormat	=	getDateFromW3CDTF(date);
					var dateString		=	getStringFromDate(dateWithFormat.date,3);
					return dateString;
				}
			var formatSubjects
				=	function(ary){
					return ary;
				}

			var title		=	formatTitles(comment.titles);
			var link		=	formatLinks(comment.links);
			var description	=	formatDescriptions(comment.descriptions);
			var date		=	formatDates(comment.dates);
			var subjects	=	formatSubjects(comment.subjects);

			var subject		=	map(subjects.sort(),function(str){return "["+str+"]"}).join("");

			var commentElement		=	document.createElement("div");
			var dateElement			=	document.createElement("span");
			var linkElement			=	document.createElement("span");
			var subjectElement		=	document.createElement("span");
			var descriptionElement	=	document.createElement("span");
			var linka				=	document.createElement("a");

			linka.setAttribute("href",link);
			linka.setAttribute("target","_blank");
			linkElement.appendChild(linka);

			setInnerText(dateElement,date);
			setInnerText(linka,title);
			setInnerText(subjectElement,subject);
			setInnerText(descriptionElement,description);

			commentElement.setAttribute("style","margin:2px 0px;padding 0px;");
			dateElement.setAttribute("style","margin:0px 2px;");
			linkElement.setAttribute("style","margin:0px 2px;");
			subjectElement.setAttribute("style","margin:0px 2px;color:#666666;");
			descriptionElement.setAttribute("style","margin:0px 2px;");

			commentElement.appendChild(dateElement);
			commentElement.appendChild(linka);
			commentElement.appendChild(subjectElement);
			commentElement.appendChild(descriptionElement);

			return commentElement;

		}

	var getElementsByXPath
		=	function(dom,xpath){
			var snapshots	=	document.evaluate(
				xpath									,
				dom										,
				null									,
				XPathResult.ORDERED_NODE_SNAPSHOT_TYPE	,
				null
			);
			var elements=[];
			for(var i=0;i<snapshots.snapshotLength;i++){
				elements.push(snapshots.snapshotItem(i));
			}
			return elements;
		}

	var debugLog
		=	function(){
			if(DEBUG_FLAG){
				for(var i=0;i<arguments.length;i++){
					GM_log(arguments[i]);
				}
			}
		}

	var map
		=	function(ary,mthd){
			var rtn=[];
			var len=ary.length;
			for(var i=0;i<len;i++){
				rtn.push(mthd(ary[i]));
			}
			return rtn;
		}

	var getInnerText
		=	function(ele){
			var val;
			switch(true){
				case ("innerText" in ele)	:	val=ele.innerText	;	break	;
				case ("textContent" in ele)	:	val=ele.textContent	;	break	;
				default						:						;	break	;
			}
			return val;
		}

	var setInnerText
		=	function(ele,val){
			switch(true){
				case ("innerText" in ele)	:	ele.innerText=val	;	break	;
				case ("textContent" in ele)	:	ele.textContent=val	;	break	;
				default						:						;	break	;
			}
		}

	var getDateFromW3CDTF
		=	function(W3CDTF){

			var formatType=0;
			var fullyear="1970",month="01",date="01",
				hours="00",minutes="00",seconds="00",milliseconds="0",
				signTZ="+",hoursTZ="00",minutesTZ="00";

			switch(true){
				case (result=W3CDTF.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\.(\d)([+-])(\d{2}):(\d{2})$/))!=null:
					formatType=7;
					fullyear=result[1],month=result[2],date=result[3],
					hours=result[4],minutes=result[5],seconds=result[6],milliseconds=result[7],
					signTZ=result[8],hoursTZ=result[9],minutesTZ=result[10];
					break;
				case (result=W3CDTF.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})([+-])(\d{2}):(\d{2})$/))!=null:
					formatType=6;
					fullyear=result[1],month=result[2],date=result[3],
					hours=result[4],minutes=result[5],seconds=result[6],
					signTZ=result[7],hoursTZ=result[8],minutesTZ=result[9];
					break;
				case (result=W3CDTF.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})([+-])(\d{2}):(\d{2})$/))!=null:
					formatType=5;
					fullyear=result[1],month=result[2],date=result[3],
					hours=result[4],minutes=result[5],
					signTZ=result[6],hoursTZ=result[7],minutesTZ=result[8];
					break;
				case (result=W3CDTF.match(/^(\d{4})-(\d{2})-(\d{2})$/))!=null:
					formatType=3;
					fullyear=result[1],month=result[2],date=result[3];
					break;
				case (result=W3CDTF.match(/^(\d{4})-(\d{2})$/))!=null:
					formatType=2;
					fullyear=result[1],month=result[2];
					break;
				case (result=W3CDTF.match(/^(\d{4})$/))!=null:
					formatType=1;
					fullyear=result[1];
					break;
				default:
			}

			var time=new Date(0);
			time.setUTCFullYear(parseInt(fullyear,10));
			time.setUTCMonth(parseInt(month,10)-1);
			time.setUTCDate(parseInt(date,10));
			time.setUTCHours(parseInt(hours,10));
			time.setUTCMinutes(parseInt(minutes,10));
			time.setUTCSeconds(parseInt(seconds,10));
			time.setUTCMilliseconds(parseInt(milliseconds,10)*100);
			var timeZone	=	parseInt(hoursTZ,10)*60+parseInt(minutesTZ,10);
			timeZone		=	((signTZ=="-")?-timeZone:timeZone);
			time.setTime(time.getTime()-timeZone*60*1000);

			return {date:time,formatType:formatType};

		}

	var getStringFromDate
		=	function(date,formatType){
			var rtn="";
			switch(formatType){
			case 7:	rtn	=	"."	+	(	"000"	+	(	date.getMilliseconds()	+	0	)	.toString(10)	).slice(-3)+rtn;
			case 6:	rtn	=	":"	+	(	"00"	+	(	date.getSeconds()		+	0	)	.toString(10)	).slice(-2)+rtn;
			case 5:	rtn	=	":"	+	(	"00"	+	(	date.getMinutes()		+	0	)	.toString(10)	).slice(-2)+rtn;
			case 4:	rtn	=	" "	+	(	"00"	+	(	date.getHours()			+	0	)	.toString(10)	).slice(-2)+rtn;
			case 3:	rtn	=	"/"	+	(	"00"	+	(	date.getDate()			+	0	)	.toString(10)	).slice(-2)+rtn;
			case 2:	rtn	=	"/"	+	(	"00"	+	(	date.getMonth()			+	1	)	.toString(10)	).slice(-2)+rtn;
			case 1:	rtn	=	""	+	(	"0000"	+	(	date.getFullYear()		+	0	)	.toString(10)	).slice(-4)+rtn;
			}
			return rtn;
		}

	var onLoad
		=	function(){
			if(window.self!=window.top){
				return;
			}
			var widget=new DisplayHatenaBookmarkComments();
			var opt={
				"id":"http://www.kanasansoft.com/HaBCoDisp",
				"name":"HaBCoDisp",
				"icon":widget.dockIcon,
				"body":widget.mainArea
			};
			if(!("_USWidgetManager_" in window)){
				window._USWidgetManager_={};
			}
			if(!("widgets" in window._USWidgetManager_)){
				window._USWidgetManager_.widgets=[];
			}
			window._USWidgetManager_.widgets.push(opt);
			if(window._USWidgetManager_.noticeAddWidgets){
				window._USWidgetManager_.noticeAddWidgets();
			}
		}

	window.addEventListener("load",onLoad,true);

})();
