// ==UserScript==
// @name          Hatena Keyword
// @namespace     http://c--v.net/
// @include       *
// ==/UserScript==
//
// Mail: ryosuke a sekido dot info
// Home: http://c--v.net/
// License: Creative Commons by 2.1 Japan
//

(function() {
	// 選択されたノードの親を処理するか
	var parentNode = 1;
	// 変換するキーワードの閾値（0-50）
	var keywordScore = 10;
	// 変換対象のエレメント保存用
	var target = null;

	// メニューへ追加する
	GM_registerMenuCommand('for devel', selectElem, 'j', 'control alt');

	// エレメントの選択を促す
	function selectElem()
	{
		// イベントリスナを追加する
		var ele = document.getElementsByTagName("*");
		for (i = 0; i < ele.length; i++) {
			ele[i].addEventListener('click', onClicked, false);
			ele[i].style.cursor = "help";
		}
	}

	// クリックされたときの処理
	function onClicked(e)
	{
		// イベントリスナを削除する
		var ele = document.getElementsByTagName("*");
		for(i = 0; i < ele.length; i++) {
			ele[i].removeEventListener('click', onClicked, false);
			ele[i].style.cursor = "";
		}

		// 選択されたノードを処理する
		changeTarget(e.target);
	}

	// 選択されたエレメントの処理
	function changeTarget(e)
	{
		// 処理ノードを決定
		if (parentNode) e = e.parentNode;
		target = e;

		// クエリを生成する
		postData = '<?xml version="1.0" encoding="UTF-8"?><methodCall><methodName>hatena.setKeywordLink</methodName><params><param><value><struct><member><name>body</name><value>' + e.innerHTML + '</value></member><member><name>score</name><value><i4>' + keywordScore + '</i4></value></member></struct></value></param></params></methodCall>';

		// リクエストを送る
		GM_xmlhttpRequest({
			method: 'POST',
			url: 'http://d.hatena.ne.jp/xmlrpc',
			onload: onLoad,
			data: postData
		});
	}

	// 変換後の結果を受け取ったとき
	function onLoad(e)
	{
		// xmlhtmlRequest の responseXML もどき
		// From: http://d.hatena.ne.jp/Yuichirou/20060830#1156906213
		e.responseXML = (new DOMParser).parseFromString(e.responseText, "application/xml");
		var ele = e.responseXML.documentElement;

		// 対象ノードを置き換える
		$X('//params/param/value/string', ele).forEach(function (i) {
			if (target) {
				var text = i.textContent;
				text = text.replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"');
				target.innerHTML = text;
			}
		});

		// 処理終了
		target = null;
	}

	/* template functions
	 * -- Original: http://lowreal.net/logs/2006/03/16/1 by cho45
	 */
	function $X (exp, context) {
		if (!context) context = document;
		var resolver = function (prefix) {
			var o = document.createNSResolver(context)(prefix);
			return o ? o : (document.contentType == "text/html") ? "" : "http://www.w3.org/1999/xhtml";
		}
		var exp = document.createExpression(exp, resolver);

		var result = exp.evaluate(context, XPathResult.ANY_TYPE, null);
		switch (result.resultType) {
			case XPathResult.STRING_TYPE : return result.stringValue;
			case XPathResult.NUMBER_TYPE : return result.numberValue;
			case XPathResult.BOOLEAN_TYPE: return result.booleanValue;
			case XPathResult.UNORDERED_NODE_ITERATOR_TYPE: {
				result = exp.evaluate(context, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
				var ret = [];
				for (var i = 0, len = result.snapshotLength; i < len ; i++) {
					ret.push(result.snapshotItem(i));
				}
				return ret;
			}
		}
		return null;
	}
})();
