////////////////////////////////////////////////////////////////////////////////
//
//  calendar.js
//


function Calendar(id, caption, parentNode){

	this.id                =id;
	this.caption           =caption;
	this.date              =new Date();
	this.pageYear          =null;
	this.pageMonth         =null;
	this.callbackClick     =null;
	this.callbackDblclick  =null;
	this.callbackClose     =null;
	this.divRoot           =null;
	this.opacity           =1.0;
	this.timer             =null;

	Calendar.map[id] =this;

	//日付の設定
	this.setDate =function (year, month, day){

		this.date =new Date(year, month -1, day);
		this.setPage(year, month);

		return;
	}

	//ページ (表示月) の設定
	this.setPage =function (pageYear, pageMonth){

		var year       =this.date.getFullYear();
		var month      =this.date.getMonth() + 1;
		var day        =this.date.getDate();
		var date_first =new Date(pageYear, pageMonth - 1, 1);
		var date_last  =new Date(pageYear, pageMonth,     0);
		var pageDay    =1 - date_first.getDay();
		var len        =date_last.getDate();

		var divPage =divRoot.childNodes[1];
		divPage.childNodes[1].data =pageYear + "年" + ((pageMonth < 10) ? " " + pageMonth : pageMonth.toString()) + "月";

		var table =divRoot.childNodes[2];

		var i, j;
		for (j=0; j<6; ++j){

			var tr =table.childNodes[0].childNodes[j + 1];

			for (i=0; i<7; ++i){

				td =tr.childNodes[i];
				td.innerHTML =(0 < pageDay && pageDay <= len) ? pageDay.toString() : "";

				var classesOld =td.getAttribute("class").split(" ");
				var classNew   =(pageDay == day && month == pageMonth && year == pageYear)  ? classesOld[0] + " sel" : classesOld[0];
				td.setAttribute("class",      classNew);
				td.setAttribute("className",  classNew);

				++pageDay;
			} // i
		} // j

		this.pageYear  =pageYear;
		this.pageMonth =pageMonth;

		return;
	};

	//位置の設定
	this.setPos =function (x, y){

		this.divRoot.style.left =x + "px";
		this.divRoot.style.top  =y + "px";

		return null;
	};


	//表示状態を設定
	this.show =function (shown){

		this.divRoot.style.display =(shown || shown == undefined) ? "block" : "none";

		return null;
	};

	//非表示状態に設定
	this.hide =function (){
		return this.show(false);
	};

	//フェードイン
	this.fadein =function(){

		var divRoot =this.divRoot;
		if (divRoot.style.display != "none") return false;

		divRoot.style.filter  ="alpha(opacity=0)";
		divRoot.style.opacity ="0";
		divRoot.style.display ="block";

		var timer =setInterval("Calendar.fadeinProc(\"" + this.id + "\");", 50);

		if (this.timerID) this.killTimer();
		this.timer      =timer;
		this.timerCount =0;

		return true;
	};

	//フェードアウト
	this.fadeout =function(){

		var divRoot =this.divRoot;
		if (divRoot.style.display == "none") return false;

		divRoot.style.filter  ="alpha(opacity=" + 100*this.opacity + ")";
		divRoot.style.opacity =this.opacity.toString();

		var timer =setInterval("Calendar.fadeoutProc(\"" + this.id + "\");", 50);
		if (this.timerID) this.killTimer();

		this.timer      =timer;
		this.timerCount =0;

		return true;
	};



	//フェードイン用プロシジャ [for internal use]
	Calendar.fadeinProc =function(id){

		var sbj      =Calendar.map[id];
		var divRoot =sbj.divRoot;

		if (sbj.timerCount < 5){

			var opacity =++sbj.timerCount*sbj.opacity/5;

			divRoot.style.opacity =opacity.toString();
			divRoot.style.filter  ="alpha(opacity=" + 100*opacity + ")";
		}
		else {
			sbj.killTimer();
		}

		return true;
	};

	//フェードアウト用プロシジャ [for internal use]
	Calendar.fadeoutProc =function(id){

		var sbj     =Calendar.map[id];
		var divRoot =sbj.divRoot;

		if (sbj.timerCount < 5){

			var opacity =(5 - ++sbj.timerCount*sbj.opacity)/5;

			divRoot.style.opacity =opacity.toString();
			divRoot.style.filter  ="alpha(opacity=" + 100*opacity + ")";
		}
		else {
			divRoot.style.display ="none";
			sbj.killTimer();
		}

		return true;
	};









	//タイマの破棄 [for internal use]
	this.killTimer =function (){

		if (!this.timer) return false;

		clearInterval(this.timer);
		this.timer =null;

		return true;
	}

	//クリックコールバックの設定
	this.setClickCallback =function (callback){
		this.callbackClick =callback;
	}

	//ダブルクリックコールバックの設定
	this.setDblclickCallback =function (callback){
		this.callbackDblclick =callback;
	}

	//閉じるコールバックの設定
	this.setCloseCallback =function (callback){
		this.callbackClose =callback;
	}

	//callback functions (caption) ---------------------------------------

	//キャプションのグラブ処理
	Calendar.onCaptionGrabbed =function (e){

		var divCaption =Calendar.getEventTarget(e);

		var sbj =Calendar.map[divCaption.parentNode.id];
		if (!sbj) return true;

		Calendar.objGrabbed =sbj;
		Calendar.gripX      =(e.offsetX ? e.offsetX : e.layerX) + 4;
		Calendar.gripY      =(e.offsetY ? e.offsetY : e.layerY) + 4;

		divCaption.style.cursor ="move";

		return false;
	}

	//キャプションの解放処理
	Calendar.onCaptionReleased =function (e){

		var sbj =Calendar.objGrabbed;
		if (!sbj) return true;

		var divCaption =sbj.divRoot.childNodes[0];
		divCaption.style.cursor ='default';

		Calendar.objGrabbed =null;
		Calendar.gripX      =null;
		Calendar.gripY      =null;

		return false;
	}

	//キャプションのドラッグ処理
	Calendar.onCaptionDragged =function(e){

		var sbj =Calendar.objGrabbed;
		if (!sbj) return true;

		if (!e) e =event;

		var x =e.clientX - Calendar.gripX + document.body.scrollLeft;
		var y =e.clientY - Calendar.gripY + document.body.scrollTop;

		//alert(Calendar.gripX + "px");

		var divRoot =sbj.divRoot;
		divRoot.style.left =x + "px";
		divRoot.style.top  =y + "px";

		return false;
	}

	//「閉じる」ボタンのクリック処理
	Calendar.onClosed =function(e){

		var spanClose =Calendar.getEventTarget(e);
		var divRoot   =spanClose.parentNode.parentNode;
		var sbj       =Calendar.map[divRoot.id];

		if (!sbj.callbackClose || sbj.callbackClose(sbj)){
			sbj.hide();
		}

		return false;
	}


	//callback (page control) --------------------------------------------------

	//「前月」へ移動 (for Internet Explorer)
	Calendar.onPagePrev =function (e){

		var sbj  =Calendar.map[Calendar.getEventTarget(e).parentNode.parentNode.id];
		var prev =new Date(sbj.pageYear, (sbj.pageMonth - 1) - 1, 1);

		sbj.setPage(prev.getFullYear(), prev.getMonth() + 1);

		return false;
	}

	//「翌月」へ移動 (for Internet Explorer)
	Calendar.onPageNext =function(e){

		var sbj  =Calendar.map[Calendar.getEventTarget(e).parentNode.parentNode.id];
		var next =new Date(sbj.pageYear, (sbj.pageMonth - 1) + 1, 1);

		sbj.setPage(next.getFullYear(), next.getMonth() + 1);

		return false;
	}


	//callback (day cell) ------------------------------------------------------

	//セルのポイント処理
	Calendar.onCellPointed =function (e){

		if (Calendar.objGrabbed) return true;

		var td  =Calendar.getEventTarget(e);
		var sbj =Calendar.map[td.parentNode.parentNode.parentNode.parentNode.id];

		var day =parseInt(td.innerHTML);
		day =parseInt(td.innerHTML);

		if (isNaN(day) || day == sbj.date.getDate()) return true;

		var attrNew =td.getAttribute("class").slice(0, 3) + " ptd";

		td.setAttribute("class",     attrNew);
		td.setAttribute("className", attrNew);

		return false;
	}

	//セルのポイント解除処理
	Calendar.onCellDepointed =function (e){

		var td  =Calendar.getEventTarget(e);
		var sbj =Calendar.map[td.parentNode.parentNode.parentNode.parentNode.id];

		var day =parseInt(td.innerHTML);
		if (isNaN(day) || day == sbj.date.getDate()) return true;

		var attrNew =td.getAttribute("class").slice(0, 3);

		td.setAttribute("class",     attrNew);
		td.setAttribute("className", attrNew);

		return false;
	}

	//セルのクリック処理
	Calendar.onCellClicked = function(e){

		var td  =Calendar.getEventTarget(e);
		var day =parseInt(td.innerHTML);

		if (isNaN(day)) return false;

		var tbody   =td.parentNode.parentNode
		var divRoot =tbody.parentNode.parentNode
		var sbj     =Calendar.map[divRoot.id]

		var callback =sbj.callbackClick;		
		if (callback && !callback(sbj, sbj.pageYear, sbj.pageMonth, day)){
			return false;
		}

		var i, j;
		for (j=0; j<6; ++j){

			var tr =tbody.childNodes[j + 1];

			for (i=0; i<7; ++i){

				var tdT  =tr.childNodes[i];
				var dayT =parseInt(tdT.innerHTML);

				var attrNew =(dayT == day)
					? tdT.getAttribute("class").slice(0, 3) + " sel"
					: tdT.getAttribute("class").slice(0, 3);

				tdT.setAttribute("class",     attrNew);
				tdT.setAttribute("className", attrNew);
			} // i
		} // j

		sbj.date =new Date(sbj.pageYear, sbj.pageMonth - 1, day);

		return true;
	}

	//セルのダブルクリック処理
	Calendar.onCellDblclk =function (e){

		var td  =Calendar.getEventTarget(e);
		var day =parseInt(td.innerHTML);

		if (isNaN(day)) return true;

		var sbj =Calendar.map[td.parentNode.parentNode.parentNode.parentNode.id]

		if (sbj.callbackDetermine){
			var date =sbj.date;
			sbj.callbackDetermine(sbj, date.getFullYear(), date.getMonth() + 1, date.getDate());
		}

		return true;
	}

	//other functions ----------------------------------------------------------

	//要素ノードの作成 [for intenal use]
	Calendar.createElement =function(name, parentNode){

		node  =document.createElement(name);
		parentNode.appendChild(node);

		return node;
	}

	//テキストノードの作成・追加 [for internal use]
	Calendar.createTextNode =function (text, parentNode){

		node =document.createTextNode(text);
		parentNode.appendChild(node);

		return node;
	}

	//イベントハンドラの設定
	Calendar.registerEvent =function (elem, name, handler){

		if (elem.addEventListener){ //DOM
			return elem.addEventListener(name, handler, false);
		}
		if (elem.attachEvent){ //Internet Explorer
			return elem.attachEvent("on" + name, function(e) { handler.call(elem, e); } );
		}

		elem["on" + name] = handler;

		return true;
	}

	//イベントターゲットの取得
	Calendar.getEventTarget =function (e){

		if (e.target    ){ //DOM
			return e.target;
		}
		if (e.srcElement){ //Internet Explorer
			return e.srcElement;
		}
	}


	//--------------------------------------------------------------------------

	var divRoot =document.createElement('div');
	divRoot.id =id;
	divRoot.style.position  ="absolute";
	divRoot.style.display   ="none";

	divRoot.setAttribute("class",     "calendar");
	divRoot.setAttribute("className", "calendar");

	//caption bar ----------------------------------------------

	var divCaption =Calendar.createElement('div', divRoot)
	divCaption.setAttribute("class",     "caption");
	divCaption.setAttribute("className", "caption");
	divCaption.style.verticalAlign ="middle";
	divCaption.innerHTML =caption;

	Calendar.registerEvent(divCaption, "mousedown", Calendar.onCaptionGrabbed);
	Calendar.registerEvent(divCaption, "mouseup",   Calendar.onCaptionReleased);
	Calendar.registerEvent(divCaption, "mousemove", Calendar.onCaptionDragged);

	var spanClose =Calendar.createElement('div', divCaption);
	spanClose.style.position        ="absolute";
	spanClose.style.top             ="0";
	spanClose.style.right           ="0";
	spanClose.style.margin          ="2px";
	spanClose.style.color           ="black";
	spanClose.style.backgroundColor ="#d0d0d0";
	spanClose.style.padding         ="1px 0 0 1px";
	spanClose.style.border          ="solid 1px #a0a0a0";
	spanClose.style.cursor          ="pointer";
	spanClose.innerHTML             ="&times;"

	Calendar.registerEvent(spanClose, "click", Calendar.onClosed);

	//page contrl ----------------------------------------------

	var divMonth =Calendar.createElement('div', divRoot)

	divMonth.setAttribute("class",     "month");
	divMonth.setAttribute("className", "month");

	var spanPrev =Calendar.createElement("span", divMonth);
	spanPrev.style.marginRight ="1.0em";
	spanPrev.style.cursor     ="pointer";
	spanPrev.innerHTML         ="&lt;&lt;";

	Calendar.createTextNode("----年--月", divMonth);

	var spanNext =Calendar.createElement("span", divMonth);
	spanNext.style.marginLeft ="1.0em";
	spanNext.style.cursor     ="pointer";
	spanNext.innerHTML        ="&gt;&gt;";
	

	Calendar.registerEvent(spanPrev, "click", Calendar.onPagePrev);
	Calendar.registerEvent(spanNext, "click", Calendar.onPageNext);

	//table ----------------------------------------------------

	var table =Calendar.createElement('table', divRoot);
	var tbody =Calendar.createElement('tbody', table);

	{ //wday header
		var tr =Calendar.createElement('tr', tbody);

		var i;
		for (i=0; i<7; ++i){
			var th =Calendar.createElement('th', tr);
			th.setAttribute('class',     Calendar.WDAY_CLASS[i]);
			th.setAttribute('className', Calendar.WDAY_CLASS[i]);
			th.innerHTML =Calendar.WDAY_NAME[i];
		}
	}

	var j;
	for (j=0; j<6; ++j){
		var tr =Calendar.createElement('tr', tbody);
		var i;
		for (i=0; i<7; ++i){
			var td =Calendar.createElement('td', tr);

			td.setAttribute('class',     Calendar.WDAY_CLASS[i]);
			td.setAttribute('className', Calendar.WDAY_CLASS[i]);
			td.innerHTML ='-';

			Calendar.registerEvent(td, "mouseover", Calendar.onCellPointed);
			Calendar.registerEvent(td, "mouseout",  Calendar.onCellDepointed);
			Calendar.registerEvent(td, "click",     Calendar.onCellClicked);
			Calendar.registerEvent(td, "dblclick",  Calendar.onCellDblclk);
		} //i
	} //j

	this.setPage(this.date.getFullYear(), this.date.getMonth() + 1);

	this.divRoot =divRoot;
	parentNode.appendChild(divRoot);


	if (!Calendar.initialized){
		document.onmouseup   =Calendar.onCaptionReleased;
		document.onmousemove =Calendar.onCaptionDragged;
		Calendar.initialized =true;
	}

	return this;
}

Calendar.initialized =false;
Calendar.map         =[];
Calendar.objGrabbed  =null;
Calendar.gripX       =0;
Calendar.gripY       =0;
Calendar.WDAY_CLASS  =[ 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat' ];
Calendar.WDAY_NAME   =[ '日',  '月',  '火',  '水',  '木',  '金',  '土'  ];

