// Tab設定は2。

// --- from  prototype.js ------------------------------------------------------------------------
Function.prototype.bind = function(){
  var __method = this, args = $A(arguments), object = args.shift();
  return function() {
    return __method.apply(object, args.concat($A(arguments)));
  }
};

function $A(iterable) {
  if (!iterable) return [];
  if (iterable.toArray) return iterable.toArray();
  var length = iterable.length || 0, results = new Array(length);
  while (length--) results[length] = iterable[length];
  return results;
}
// -----------------------------------------------------------------------------------------------

// --- from  yanejslib.js ------------------------------------------------------------------------

// イベントリスナに追加する。
function addEvent(eventName , callbackFunction)
{
	window.addEventListener ?
	  window.addEventListener(eventName,callbackFunction, false) :
	  window.attachEvent('on'+eventName,callbackFunction );
}

// css class名から、そのelement一覧を返すhelper
function getElementsByClass(className)
{
    var classElements = new Array();
    var allElements = document.getElementsByTagName('*');
    for (var i = 0 ; i < allElements.length; i++)
		{
			if (allElements[i].className == className)
			    classElements.push( allElements[i] );
    }
    return classElements;
}

//	HTML elementの直前に別のelementを挿入する。
function insertBefore(targetElement,insertElement)
{
			var parent = targetElement.parentNode;

			//	次の要素はnextSiblingで辿れるのでinsertBeforeすれば良いのだが、
			//	最後の要素だとnextSiblingがnullになるのでその場合はappendChildする。
			parent.insertBefore(insertElement,targetElement);
}

//	HTML elementの直後に別のelementを挿入する。
function insertAfter(targetElement,insertElement)
{
			var parent = targetElement.parentNode;

			//	次の要素はnextSiblingで辿れるのでinsertBeforeすれば良いのだが、
			//	最後の要素だとnextSiblingがnullになるのでその場合はappendChildする。
			if (targetElement.nextSibling)
				parent.insertBefore(insertElement,targetElement.nextSibling);
			else
				parent.appendChild(insertElement);
}

// 文字列を解析する
var StringParser =
{
	create : function (str)
	{
			this.str = str;
			return this;
	},

	str:"",		// 保持している文字列

	// もし保持している文字列が先頭がtargetと一致したら、それを除去してtrueを返し、
	// this.strはその一致した文字列を除去したものに変更する。
	startWith : function (target)
	{
		if ( /*this.str.indexOf(target) == 0*/
				this.str.substr(0,target.length) == target )
		{
			this.str = this.str.slice(target.length);
			return true;
		}
		return false;
	}
};

// addEvent('load',o.startUp.bind(o) ); の省略記法
function startUp(o)
{
	addEvent('load',o.startUp.bind(o));
}

// -----------------------------------------------------------------------------------------------
// 本文の自動整形システム
var autoblog = {
	high_lighten : function(str)
	{
		// JavaScript/C#のキーワードをハイライト
		var keyword = [ "class","internal","var","function","if","new","object","string","for","true","false","undefined","bool",
			"int","ulong","long","public","static","get","set","null","return","namespace","using","extern"];
			// "class"は最初にしないと、他のキーワードを置換してclassが指定されているところがさらに置換されてしまう(´ω｀)

		// C#で青緑でハイライトするキーワード
		var keyword2 = ["IntPtr","MarshalAs","UnmanagedType","DllImport"];

		for(var i=0; i<keyword.length ; ++i)
		{
			var regex = new RegExp('('+keyword[i]+')' ,"g");
			str = str.replace( regex , "<span class='textCodeKeyword'>$1</span>");
		}

		for(var i=0; i<keyword2.length ; ++i)
		{
			var regex = new RegExp('('+keyword2[i]+')' ,"g");
			str = str.replace( regex , "<span class='textCodeKeyword2'>$1</span>");
		}

		// コメント
		str = str.replace( /([ \t;])(\/\/.*)/ , "$1<span class='textCodeComment'>$2</span>" );
		// '//'の直前はスペースかタブか&nbsp; の';'のいずれかである必要がある。

		return str;
	},

	// はてなブックマークの画像などの読み込み用のフォルダ
	image_path : "../blogparts/",

  footer : "* このページに対するコメント\n\nはてなブックマークや、以下の掲示板をお使いください。\n# コメント用掲示板\nYaneu Labs掲示板\nhttp://yaneu.com/bbs/test/read.cgi/yaneurao/1236328174/l50\n",

	parseText : function(text)
	{
			text = text + this.footer;

			// 事前にまとめて除去しといたる(´ω｀)
			text = text.replace(/\r/g,"");

			var lines = text.split("\n");
			// IEだとpreタグ内の改行は、"\r\n"として保持しているが、Chromeだと\nとしてしか保持していない。
			// そこで \nでsplitして、\rを除去する必要があるが、毎行\rを除去するのは嫌なので先頭で一括して除去している。
			// ( 除去しなくとも問題はないと思うのだが…。)

			var newlines = [];
			var textMode = 0;

			var anchorCount = 0;
			var subAnchorCount = 0;
			var titledBoxCount = 0; // タイトルボックス

			for(var i = 0; i< lines.length ; ++i)
			{
				var line = lines[i];
				var parser = StringParser.create(line);
				var skipBr = false;

				if (parser.startWith("<pre>") || parser.startWith("<PRE>"))
				{
					// IEは何故かpreを勝手に大文字化して保持している。

					// preタグは除去する。このあとに文字が続くのでそれはparseする。
				}
				if (parser.startWith("</pre>") || parser.startWith("</PRE>"))
				{

				}

				// httpで始まる部分は、ハイパーリンクにする。
				parser.str = parser.str.replace( /(http:\/\/[\x21-\x7e]+)/g , "<a class='topLINK' href='$1'><img src='"+this.image_path+"linkbutton.png' style='border:none;margin-bottom:-2px' alt=''> $1</a>");

				// 'ttp'は'http'と置換する。
				parser.str = parser.str.replace( /([^h])ttp/g,"$1http");

	/*
				parser.str = parser.str.replace( /\[hatefu:([\x21-\x7e\/]+):(.*)\]/ ,
					"<a href='http://b.hatena.ne.jp/entry/$1'><img src='http://b.hatena.ne.jp/entry/image/$1' alt='はてなブックマーク - YaneuLabs ' title='$2' style='border:none'></a><a href='http://b.hatena.ne.jp/entry/$1'><img src='"+image_path+"b_entry.gif' width='16' height='12' style='border: none;' alt='このエントリーを含むはてなブックマーク' title='このエントリーを含むはてなブックマーク' /></a><a href='http://labs.yaneu.com/20090309/' alt='はてな付箋' title='はてな付箋'><img src='"+image_path+"hatefu.gif' style='border:none'></a>" );
	*/

				//	id:XXX と書いてあれば、はてなダイアリーにリンクする。
				parser.str = parser.str.replace( /id:([\x21-\x7e]+)/g , "<a class='topLINK' href='http://d.hatena.ne.jp/$1/'>id:$1</a>");


			// *[hatefu:labs.yaneu.com/20090325] 画面に表示されるアイテム数を自動調整する
			// のように書いたら、自動的に、はてブと、はてふを追加する。

				var regex = new RegExp("(\\[hatefu:)([\x21-\x7e\\/]+)\\](.*)", "");
				var match = parser.str.match(regex);
				if (match!=null)
				{
					// match[2]が、'labs.yaneu.com/20090325'なので、hatefuをセットアップしておく。
					this.hatefuUrl = match[2];
				}

				parser.str = parser.str.replace(regex ,
					"$3<a href='http://b.hatena.ne.jp/entry/http://$2'><img src='"+this.image_path+"b_entry.gif' width='16' height='12' style='border: none;' alt='このエントリーを含むはてなブックマーク' title='このエントリーを含むはてなブックマーク' /></a><a href='http://b.hatena.ne.jp/entry/http://$2'><img src='http://b.hatena.ne.jp/entry/image/http://$2' alt='はてなブックマーク - YaneuLabs ' title='$3' style='border:none'></a><a href='http://labs.yaneu.com/20090309/' alt='はてな付箋' title='はてな付箋'><img src='"+this.image_path+"hatefu.gif' style='border:none'></a>" );

				// [img:ファイル名] と書いたら、画像をセンタリングして挿入。
				parser.str = parser.str.replace(/\[img:(.*)\](.*)/,"<img style='display:block;margin: 0 auto' src='$1' style='border:none'>$2");

				if (parser.startWith('* '))
				{
					// '* 'で始まる行は、タイトル行

					anchorCount ++; // 事前に加算しないと、sub sectionのアンカー番号がおかしくなる。
					parser.str = (textMode != 0 ? '</div>':'') + "<div class='textHeader'><a href='#"+ anchorCount +"'><img src='"+this.image_path+"point16.png' name='" + anchorCount + "' id='" + anchorCount + "' alt='' style='border:none'></a>　" + parser.str + "</div><div class='textGray'>";
					subAnchorCount = 0;
					textMode = 1; // 本文テキストモードに突入。
					skipBr = true;

				} else if (parser.startWith('** ')) {

					// '** 'で始まる行は、サブタイトル行
					subAnchorCount++;

					var anchorName = anchorCount +"_" + subAnchorCount;
					parser.str = "<a href='#"+ anchorName + "'><img style='margin-bottom:-2px;border:none' src='"+this.image_path+"point16br.png' alt='' name='" + anchorName + "' id='" + anchorName + "' alt='' style='border:none'></a>　" + parser.str;

				} else if (parser.startWith('>>') || parser.startWith('&gt;&gt;')) {
					// IEでは&gt;&gtとencodeして保持している。

					parser.str = (textMode != 0 ? '</div>':'')
						+ "<div class='textCode' style='border-style:solid;border-width:1px;border-color:white;width:600px;margin:0 auto;'>" + parser.str;
					textMode = 2;
					skipBr = true;

				} else if (parser.startWith('<<') || parser.startWith('&lt;&lt;')) {
					// IE,Chromeともに&lt;&ltとencodeして保持している。

					parser.str = (textMode != 0 ? '</div>':'') + "<div class='textGray'>" + parser.str;
					textMode = 1; // 本文テキストモードに突入。
				} else if (parser.startWith('# ')) {
					// titledBox
					titledBoxCount=2; // 2行固定でいいのだろうか。複数書きたいときは、<br>で書けばいいか。
					parser.str = "<div style='border:1px solid #C00000;'><div style='background-color:#800000;color:#FFFFFF;font-size:12pt;font-weight:bold;'>"
						+ parser.str + "</div>";

					skipBr = true;

				} else {
					// コードブロックなら、メタ記号をエスケープしないといけないのだが、preタグ内だから、もうすでにエスケープされている。
					// よって、スペースだけ調整してやればそれで良いのでは…。
					if (textMode == 2)
					{
						// コードブロック部のtabは2 tab設定。
						parser.str = parser.str.replace( /\t/g , "&nbsp;&nbsp;");

						// 予約語にハイライト
						parser.str = this.high_lighten(parser.str);
					}
					if (titledBoxCount)
					{
						if (--titledBoxCount!=0)
							parser.str = "<div>" + parser.str; // 2行目
						else
						{
								parser.str = parser.str + "</div></div>"; // 3行目
								skipBr = true;
						}
					}

				}

				// 最終行以外ならば改行のためのbrを入れる。
				var br = "";
				if (i != lines.length -1)
				{
						br = skipBr ? "" : "<br>\r\n";
				} else {
					 if (textMode) br = "</div>"; // テキスト本文モードなら、そのdivを閉じておく必要がある。
				}

				newlines.push(parser.str + br);
			}

			return newlines.join('');
	},

	hatefuUrl : null,	//	はてふされるべきURL

	// ブログのheader用の文字列。ここを変更して使うべし。
	blog_header_string :
		"<div id='allbox' style='width:750px;margin:0 auto'>"+
		"<div style='height:300px'><a href='http://labs.yaneu.com/'>"+
		"<img src='../image/bg.png' style='width:750px;height:300px;border:none'></a></div>"+
		"<div id='contents' class='contents'>",

	// ブログのfooter用の文字列。ここを変更して使うべし。
	blog_footer_string :
		"</div><div style='height:1.5em;background-Color:black'></div></div> <!-- all box -->",

	//	最初にこのfunctionを呼び出してください。
  startUp : function()
	{
			var elms = getElementsByClass('autoblog');
			// この範囲のテキストまるごと取得して、再構成しなおす。

			for(var i=0;i<elms.length;++i)
			{
				var e = elms[i];
				var text = e.innerHTML;

				//	このtextをparseして整形する。
				text = this.parseText(text);

				// headerとfooterを付与する。
				if (i==0) text = this.blog_header_string + text;
				if (i==elms.length-1) text = text + this.blog_footer_string;

				e.innerHTML = text;
				e.className = 'hatefu'; // はてふ可能にしてしまう。
			}

/*	// divがまたぐようなelementの挿入はしてはいけないのか…。

			// 先頭と末尾にheaderとfooterを挿入する。
			var div;
			div = document.createElement();
			div.innerHTML = this.blog_header_string;

			insertBefore(elms[0],div);

			div = document.createElement();
			div.innerHTML = this.blog_footer_string;

			insertAfter(elms[elms.length-1],div);
*/

			// はてふ用のURLが設定されているなら、はてふのスタートアップを呼び出してやる。
			if (this.hatefuUrl!=null)
				Hatefu('http://' + this.hatefuUrl);
	}
}

// autoblogのスタートアップ
startUp(autoblog);

//----------------------------------------------------------------------------------------------------
// <script language="JavaScript" type="text/javascript" src="../blogparts/jkl-dumper.js"></script>
// <script language="JavaScript" type="text/javascript" src="../blogparts/hatefu.js"></script>
// を指定するのが面倒なので、ここで以下にくっつけてしまう。

/* はてふスクリプト by yaneurao */
// http://blog.livedoor.jp/dankogai/archives/50637027.html
// http://blog.livedoor.jp/dankogai/archives/50643245.html
// を参考にさせていただいきました。

// tabは 2 tab推奨

// --- from  yanejslib.js ------------------------------------------------------------------------
function addEvent(eventName , callbackFunction)
{
	window.addEventListener ?
	  window.addEventListener(eventName,callbackFunction, false) :
	  window.attachEvent('on'+eventName,callbackFunction );
}

// css class名から、その一覧を返すhelper
function getElementsByClass(className)
{
    var classElements = new Array();
    var allElements = document.getElementsByTagName('*');
    for (var i = 0 ; i < allElements.length; i++)
		{
			if (allElements[i].className == className)
			    classElements.push( allElements[i] );
    }
    return classElements;
}
// -----------------------------------------------------------------------------------------------

function HateBJSON(callback){
	this.proxy = 'http://b.hatena.ne.jp/entry/json/';
	this.callback    = callback;
	this.parse = function(uri){
	var script = document.createElement('script'); 
	script.id = this.proxy + '?url=' + encodeURIComponent(uri) 
		+ '&callback=' + this.callback;
	script.charset = 'UTF-8';
	script.src = script.id; 

	document.lastChild.appendChild(script);
//	document.removeChild(script);
  };
  return this;
}

var Hatefu = function(url)
{
	var hatebjson = new HateBJSON('onLoadedHatebjson');
	hatebjson.parse(url /*,tagname */);
	// tagnameを動的に切り替えられるようにしようかと思ったが、
	// JSONのcallbackが静的なので複数呼び出した場合、
	// 逐次的に処理しないと、どのcallbackなのかわからなくなるんだな…。
}

function onLoadedHatebjson(json)
{
//	$('result').innerHTML = (new JKL.Dumper()).dump(json);
  if (! json) return ;

  var bm = json.bookmarks;
  if (! bm) return;

  function useruri(user){ return 'http://b.hatena.ne.jp/' + bm[i].user + '/' }
  function usericon(user){
    var src = 'http://www.hatena.ne.jp/users/' 
      + user.substr(0,2) + '/' + user + '/profile_s.gif';
    return "<img src='" + src + "' alt='" + user+ "' style='border:none'>";
  }

  function comment2str(str){
    var regex = /(http:\/\/[\x21-\x7e]+|[<>&\"])/g;
    str = str.replace(regex, function(m0,m1){
      return m1.substr(0,5) == 'http:' 
        ? '<a target="_blank" href="' + m1 + '">' + m1 + '</a>' 
        : {'<':'&lt;', '>':'&gt;','&':'&amp;', '"':'&quot;'}[m1];
    });
    return str;
  }

  // はてな付箋コメント可能領域
  var hatefu = getElementsByClass('hatefu');

  for (var i = 0; i < bm.length; i++){
//  for (var i = bm.length-1; i >=0 ; i--){
// debug用逆ループ。

     // bm[i]がuser名 , bm[i].commentがユーザーコメント。このコメントが
     // コメントに適格する場所を探して、そこに貼り付ける。

	for(var j = 0;j<hatefu.length ; j++)
	{

		var target = hatefu[j].innerHTML;
		// このなかに文字が含まれているか？

		var comment = bm[i].comment;
		if (comment=='')
			continue;

		// [hatefu]コメントをつけたい文字列:コメント
		// の書式になっているはず。

		var c = comment.split(':');
		if (c.length <= 1) continue;

		var index = target.indexOf(comment2str(c[0]));
		// c[0],c[1]から特殊文字は除外する。
		// ここではescapeするのにcomment2strを使い回す。もっとましな方法で実装すべき。

		if (index!=-1)
		{ // 見つかったのでコメントを挿入する。

			var headerStr = target.substring(0,index);

			// タグのなかにコメントを埋め込まれる可能性がある。
			// しかしcomment2strでescapeされているので、c[0],c[1]には、特殊記号は含まないので
			// タグをまたぐことはない。また、タグの内側に対するコメントは無効にする。

			// タグの内側ならばスキップ
			if (headerStr.lastIndexOf('>') < headerStr.lastIndexOf('<'))
				continue;

			// 本当は、この後続文字列に引用部があるかを判定する必要があるが、
			// こんなタグの内側にあるような紛らわしい文字列を使う奴が悪いんじゃないかと言うことで
			// それは考えないことにする。

			// 埋め込んだ「はてふ」に対してコメントされると嫌なので、user commnetの内側かどうかを
			// 判定するために、usercomment_begin～usercomment_endというidを持つダミーのdivを挿入して
			// それで判定する。

			if (headerStr.lastIndexOf('usercomment_end') < headerStr.lastIndexOf('usercomment_begin'))
				continue;

			target = headerStr
			// 引用部まで

			+"<div name='usercomment_begin' style='display:inline'></div>"

			 + "<div class='hatefu_head' style='display:inline'>" + target.substring(index,index + c[0].length) + "</div>"
			// 引用箇所の強調表示

			+ "<a href='http://labs.yaneu.com/20090309/'>"
			+ "<img src='../blogparts/hatefu.gif' alt='hatefu' style='width:16px;height:12px;border:none;display:inline'>"
			+ "</a>"
			// はてな付箋のマークを入れる。はてな付箋は、"http://labs.yaneu.com/20090309/"へリンクしておく。

			// ユーザーコメント部 色などはここで調整してください。
			+"<div style='max-width:200px;display:inline' class='hatefu_body'>"

				+ usericon(bm[i].user)
				// ユーザーアイコン

				+ "<a href=" + useruri(bm[i].user)+ ">"+ bm[i].user + "</a>"
				// ユーザー名

				+ comment2str(c[1])
				// ユーザーコメント

			 + "</div>"
			// ここはJavaScriptで書かれたpopupを埋め込んでもいいと思う。

			+"<div name='usercomment_end' style='display:inline'></div>"

			+ target.substring(index+c[0].length);

			hatefu[j].innerHTML = target;
		}
	}

  }
}
// ================================================================
//  jkl-dumper.js ---- JavaScript Object Dumper
//  Copyright 2005-2006 Kawasaki Yusuke <u-suke@kawa.net>
//  2005/05/18 - First Release
//  2006/09/04 - http://www.rfc-editor.org/rfc/rfc4627.txt
//  ===============================================================

/******************************************************************

    <script type="text/javascript" src="./jkl-dumper.js" charset="Shift_JIS"></script>
    <script><!--
        var data = {
            string: "string",
            array:  [ 1, 2, 3 ],
            hash:   { key1: "value1", key2: "value2" },
            data1:  null,
            data2:  true,
            data3:  false
        };
        var dumper = new JKL.Dumper();
        document.write( dumper.dump( data ) );
    //--></script>

******************************************************************/

if ( typeof(JKL) == 'undefined' ) JKL = function() {};

//  JKL.Dumper Constructor

JKL.Dumper = function () {
    return this;
};

//  Dump the data into JSON format

JKL.Dumper.prototype.dump = function ( data, offset ) {
    if ( typeof(offset) == "undefined" ) offset = "";
    var nextoff = offset + "  ";
    switch ( typeof(data) ) {
    case "string":
        return '"'+this.escapeString(data)+'"';
        break;
    case "number":
        return data;
        break;
    case "boolean":
        return data ? "true" : "false";
        break;
    case "undefined":
        return "null";
        break;
    case "object":
        if ( data == null ) {
            return "null";
        } else if ( data.constructor == Array ) {
            var array = [];
            for ( var i=0; i<data.length; i++ ) {
                array[i] = this.dump( data[i], nextoff );
            }
            return "[\n"+nextoff+array.join( ",\n"+nextoff )+"\n"+offset+"]";
        } else {
            var array = [];
            for ( var key in data ) {
                var val = this.dump( data[key], nextoff );
//              if ( key.match( /[^A-Za-z0-9_]/ )) {
                    key = '"'+this.escapeString( key )+'"';
//              }
                array[array.length] = key+": "+val;
            }
            if ( array.length == 1 && ! array[0].match( /[\n\{\[]/ ) ) {
                return "{ "+array[0]+" }";
            }
            return "{\n"+nextoff+array.join( ",\n"+nextoff )+"\n"+offset+"}";
        }
        break;
    default:
        return data;
        // unsupported data type
        break;
    }
};

//  escape '\' and '"'

JKL.Dumper.prototype.escapeString = function ( str ) {
    return str.replace( /\\/g, "\\\\" ).replace( /\"/g, "\\\"" );
};

//  ===============================================================


