//  ========================================================
//  jkl-calendar.js ---- ポップアップカレンダー表示クラス
//  Copyright 2005-2006 Kawasaki Yusuke <u-suke [at] kawa.net>
//  Thanks to 2tak <info [at] code-hour.com>
//  http://www.kawa.net/works/js/jkl/calender.html
//  2007.03.12 - 安達 AddinBoxの祝日判定コードを利用
//  ========================================================


// 親クラス

if ( typeof(JKL) == 'undefined' ) JKL = function() {};

// JKL.Calendar コンストラクタの定義

JKL.Calendar = function ( eid, fid, valname ) {
    this.eid = eid;
    this.formid = fid;
    this.valname = valname;
    this.__dispelem = null;  // カレンダー表示欄エレメント
    this.__textelem = null;  // テキスト入力欄エレメント
    this.__opaciobj = null;  // JKL.Opacity オブジェクト
    this.style = new JKL.Calendar.Style();
    return this;
};

// バージョン番号

JKL.Calendar.VERSION = "0.13";

// デフォルトのプロパティ

JKL.Calendar.prototype.spliter = "/";
JKL.Calendar.prototype.date = null;
JKL.Calendar.prototype.min_date = null;
JKL.Calendar.prototype.max_date = null;

// 2006.11.15 MOM 表示開始曜日をプロパティに追加(デフォルトは日曜日=0)
JKL.Calendar.prototype.start_day = 0;


// 2006.11.30 MOM 各曜日の選択可否をプロパティに追加(デフォルトは全てtrue)
// 配列の添え字で曜日を指定(0～6 = 日曜～土曜)、選択可否をboolean値で代入する、という使い方
JKL.Calendar.prototype.selectable_days = new Array(true,true,true,true,true,true,true);

// 2006.11.30 MOM カレンダーのz-indexをプロパティに追加
JKL.Calendar.prototype.zindex = 10;

// JKL.Calendar.Style

JKL.Calendar.Style = function() {
    return this;
};

// デフォルトのスタイル

// 2006.11.23 MOM 今日日付の文字色をプロパティに追加
JKL.Calendar.Style.prototype.today_color        = "#008000";    // 今日日付セルの文字色
// 2006.11.23 MOM 枠線もつけてみる
JKL.Calendar.Style.prototype.today_border_color = "#00A000";    // 今日日付セルの枠線の色
JKL.Calendar.Style.prototype.others_border_color= "#E0E0E0";    // 他の日セルの枠線の色

// 2006.11.30 MOM 今日日付の背景色を忘れてたので追加してみる
JKL.Calendar.Style.prototype.today_bgcolor      = "#D0FFD0";    // 今日日付セルの背景色
// 2006.11.30 MOM 選択不可能な日付の背景色を追加
JKL.Calendar.Style.prototype.unselectable_day_bgcolor = "#D0D0D0";    // 選択不可能な日付の背景色

//  メソッド

JKL.Calendar.Style.prototype.set = function(key,val) { this[key] = val; }
JKL.Calendar.Style.prototype.get = function(key) { return this[key]; }
JKL.Calendar.prototype.setStyle = function(key,val) { this.style.set(key,val); };
JKL.Calendar.prototype.getStyle = function(key) { return this.style.get(key); };

// 日付を初期化する

JKL.Calendar.prototype.initDate = function ( dd ) {
    if ( ! dd ) dd = new Date();
    var year = dd.getFullYear();
    var mon  = dd.getMonth();
    var date = dd.getDate();
    this.date = new Date( year, mon, date );
    this.getFormValue();
    return this.date;
}

// 透明度設定のオブジェクトを返す

JKL.Calendar.prototype.getOpacityObject = function () {
    if ( this.__opaciobj ) return this.__opaciobj;
    var cal = this.getCalendarElement();
    if ( ! JKL.Opacity ) return;
    this.__opaciobj = new JKL.Opacity( cal );
    return this.__opaciobj;
};

// カレンダー表示欄のエレメントを返す

JKL.Calendar.prototype.getCalendarElement = function () {
    if ( this.__dispelem ) return this.__dispelem;
    this.__dispelem = document.getElementById( this.eid )
    return this.__dispelem;
};

// テキスト入力欄のエレメントを返す

JKL.Calendar.prototype.getFormElement = function () {
    if ( this.__textelem ) return this.__textelem;
    var frmelms = document.getElementById( this.formid );
    if ( ! frmelms ) return;
    for( var i=0; i < frmelms.elements.length; i++ ) {
        if ( frmelms.elements[i].name == this.valname ) {
            this.__textelem = frmelms.elements[i];
        }
    }
    return this.__textelem;
};

// オブジェクトに日付を記憶する（YYYY/MM/DD形式で指定する）

JKL.Calendar.prototype.setDateYMD = function (ymd) {
    var splt = ymd.split( this.spliter );
    if ( splt[0]-0 > 0 &&
         splt[1]-0 >= 1 && splt[1]-0 <= 12 &&
         splt[2]-0 >= 1 && splt[2]-0 <= 31 ) {
        if ( ! this.date ) this.initDate();
            this.date.setDate( splt[2] );
            this.date.setMonth( splt[1]-1 );
            this.date.setFullYear( splt[0] );
    } else {
        ymd = "";
    }
    return ymd;
};

// オブジェクトから日付を取り出す（YYYY/MM/DD形式で返る）
// 引数に Date オブジェクトの指定があれば、
// オブジェクトは無視して、引数の日付を使用する（単なるfprint機能）

JKL.Calendar.prototype.getDateYMD = function ( dd ) {
    if ( ! dd ) {
        if ( ! this.date ) this.initDate();
        dd = this.date;
    }
    var mm = "" + (dd.getMonth()+1);
    var aa = "" + dd.getDate();
    if ( mm.length == 1 ) mm = "" + "0" + mm;
    if ( aa.length == 1 ) aa = "" + "0" + aa;
    return dd.getFullYear() + this.spliter + mm + this.spliter + aa;
};

// テキスト入力欄の値を返す（ついでにオブジェクトも更新する）

JKL.Calendar.prototype.getFormValue = function () {
    var form1 = this.getFormElement();
    if ( ! form1 ) return "";
    var date1 = this.setDateYMD( form1.value );
    return date1;
};

// フォーム入力欄に指定した値を書き込む

JKL.Calendar.prototype.setFormValue = function (ymd) {
    if ( ! ymd ) ymd = this.getDateYMD();   // 無指定時はオブジェクトから？
    var form1 = this.getFormElement();
    if ( form1 ) form1.value = ymd;
};

//  カレンダー表示欄を表示する

JKL.Calendar.prototype.show = function () {
    this.getCalendarElement().style.display = "block";
};

//  カレンダー表示欄を即座に隠す

JKL.Calendar.prototype.hide = function () {
    this.getCalendarElement().style.display = "none";
};

//  カレンダー表示欄をフェードアウトする

JKL.Calendar.prototype.fadeOut = function (s) {
    if ( JKL.Opacity ) {
        this.getOpacityObject().fadeOut(s);
    } else {
        this.hide();
    }
};

// 月単位で移動する

JKL.Calendar.prototype.moveMonth = function ( mon ) {
    // 前へ移動
    if ( ! this.date ) this.initDate();
    for( ; mon<0; mon++ ) {
        this.date.setDate(1);   // 毎月1日の1日前は必ず前の月
        this.date.setTime( this.date.getTime() - (24*3600*1000) );
    }
    // 後へ移動
    for( ; mon>0; mon-- ) {
        this.date.setDate(1);   // 毎月1日の32日後は必ず次の月
        this.date.setTime( this.date.getTime() + (24*3600*1000)*32 );
    }
    this.date.setDate(1);       // 当月の1日に戻す
    this.write();    // 描画する
};

// イベントを登録する

JKL.Calendar.prototype.addEvent = function ( elem, ev, func ) {
//  prototype.js があれば利用する(IEメモリリーク回避)
    if ( window.Event && Event.observe ) {
        Event.observe( elem, ev, func, false );
    } else {
        elem["on"+ev] = func;
    }
}

// カレンダーを描画する

JKL.Calendar.prototype.write = function () {
    var date = new Date();
    if ( ! this.date ) this.initDate();
    date.setTime( this.date.getTime() );

    var year = date.getFullYear();          // 指定年
    var mon  = date.getMonth();             // 指定月
    var today = date.getDate();             // 指定日
    var form1 = this.getFormElement();

    // 選択可能な日付範囲
    var min;
    if ( this.min_date ) {
        var tmp = new Date( this.min_date.getFullYear(), 
            this.min_date.getMonth(), this.min_date.getDate() );
        min = tmp.getTime();
    }
    var max;
    if ( this.max_date ) {
        var tmp = new Date( this.max_date.getFullYear(), 
            this.max_date.getMonth(), this.max_date.getDate() );
        max = tmp.getTime();
    }

    // 直前の月曜日まで戻す
    date.setDate(1);                        // 1日に戻す
    var wday = date.getDay();               // 曜日 日曜(0)～土曜(6)

// 2006.11.15 MOM 表示開始曜日を可変にしたので、ロジックちょっといじりますよ
    if ( wday != this.start_day ) {
        date.setTime( date.getTime() - (24*3600*1000)*((wday-this.start_day+7)%7) );
    }

    // 最大で7日×6週間＝42日分のループ
    var list = new Array();
    for( var i=0; i<42; i++ ) {
        var tmp = new Date();
        tmp.setTime( date.getTime() + (24*3600*1000)*i );
        if ( i && i%7==0 && tmp.getMonth() != mon ) break;
        list[list.length] = tmp;
    }

    // HTMLソースを生成する
    var src1 = "";

// 2006.11.23 MOM 邪魔な<select>への応急処置その１
// テーブルをdivで囲んで上位レイヤに設定(z-indexの値を大きくしておく)
// 2006.11.27 MOM 描画フィールドの高さを取得するため、idをセットしておく
    src1 += '<div id="calendar">\n';

    src1 += '<table border="0" cellpadding="0" cellspacing="0" id="calendar_table">';
	src1 += '<tr><th colspan="6" class="month"><a id="__'+this.eid+'_btn_today" href="javascript:void(0)">'+(year)+'年 '+(mon+1)+'月</a></th>';
	src1 += '<td class="close"><a id="__'+this.eid+'_btn_close" title="閉じる" href="javascript:void(0)"><img src="img/close.gif" alt="閉じる"></a></td></tr>';
	src1 += '<tr>';

// 2006.11.15 MOM 表示開始曜日start_dayから順に一週間分表示する
    for(var i = this.start_day; i < this.start_day + 7; i++){
        var _wday = i%7;
        if(_wday == 0){
             src1 += '<th class="sunday">SUN</th>';
        }else if(_wday == 6){
             src1 += '<th class="saturday"">SAT</th>';
        }else{
             src1 += '<th ';
            if(_wday == 1)        src1 += 'class="weekday">MON</th>';
            else if(_wday == 2)    src1 += 'class="weekday">TUE</th>';
            else if(_wday == 3)    src1 += 'class="weekday">WED</th>';
            else if(_wday == 4)    src1 += 'class="weekday">THU</th>';
            else if(_wday == 5)    src1 += 'class="weekday">FRI</th>';
        }
    }

    src1 += "</tr>\n";

    var curutc;
    if ( form1 && form1.value ) {
        var splt = form1.value.split(this.spliter);
        if ( splt[0] > 0 && splt[2] > 0 ) {
            var curdd = new Date( splt[0]-0, splt[1]-1, splt[2]-0 );
            curutc = curdd.getTime();                           // フォーム上の当日
        }
    }

//2006.11.23 MOM 今日日付を取得し、時分秒を切り捨てる
    var realdd = new Date();
    var realutc = (new Date(realdd.getFullYear(),realdd.getMonth(),realdd.getDate())).getTime();

    for ( var i=0; i<list.length; i++ ) {
        var dd = list[i];
        var ww = dd.getDay();
        var mm = dd.getMonth();

        if ( ww == this.start_day ) {
            src1 += "<tr>";                                     // 表示開始曜日の前に行頭
        }

        var utc = dd.getTime();

//2007.03.12 安達 祝日判定追加
//2007.03.25 1月と12月頁の当月外の祝日判定バグを修正
	var ss = this.getDateYMD(dd);
	var getholiday = ktHolidayName(ss);




// 2006.11.30 MOM 選択可能な曜日指定の条件追加

		if ( utc == curutc ) {                                  // フォーム上の当日
			cc += "";
		}else if ( mon == mm && utc == realutc ){	// 2006.11.30 MOM 今日日付の背景色
			cc += "today";
        }
        var ss = this.getDateYMD(dd);

        var tt = dd.getDate();
		
		if(( min && min > utc ) || ( max && max < utc ) || ( !this.selectable_days[dd.getDay()] )){
			if(ww==0 || getholiday !=""){
				src1 += '<td class="no_sun" title="'+ss+''+getholiday+'">';
			}else{
				src1 += '<td class="no_select" title="'+ss+''+getholiday+'">';
			}
		}else if(ww==0 || getholiday !=""){
			src1 += '<td class="sunday" title="'+ss+''+getholiday+'">';
		}else if(ww==6){
			if(mon !== mm){
				src1 += '<td class="om_sat" title="'+ss+''+getholiday+'">';
			}else{
				src1 += '<td class="saturday">';
			}
		}else{
			if(mon !== mm || ww==2){
				src1 += '<td class="om_week" title="'+ss+''+getholiday+'">';
			}else{
				src1 += '<td class="weekday">';
			}
		}

		var toDay = new Date();
		var toD = toDay.getDate();

		if(( min && min > utc ) || ( max && max < utc ) || ( !this.selectable_days[dd.getDay()] )){
			if(ww==0 || getholiday !=""){
				src1 += tt;
			}else{
				src1 += tt;
			}
		}else if(ww==0 || getholiday !=""){//日曜
			if(tt == toD||tt == toD + 1||tt == toD + 2||tt == toD + 3){
				src1 += tt;
			}else{
				src1 += '<a title="'+ss+''+getholiday+'" id="__'+this.eid+'_td_'+ss+'" href="javascript:void(0);">'+tt+'</a>';
			}
		}else if(ww==6){//土曜
			if(mon !== mm){
				src1 += tt;
			}else{
				if(tt == toD||tt == toD + 1||tt == toD + 2||tt == toD + 3){
					src1 += tt;
				}else{
					src1 += '<a title="'+ss+''+getholiday+'" id="__'+this.eid+'_td_'+ss+'" href="javascript:void(0);">'+tt+'</a>';
				}
			}
		}else{//平日
			if(mon !== mm){
				src1 += tt;
			}else{
				var ___this = this;
				var todayToD = new Date();
				if(todayToD.getMonth() == ___this.date.getMonth()){
					if(tt == toD||tt == toD + 1||tt == toD + 2||tt == toD + 3||ww==2){//3日以内
						src1 += tt;
					}else{
						src1 += '<a title="'+ss+''+getholiday+'" id="__'+this.eid+'_td_'+ss+'" href="javascript:void(0);">'+tt+'</a>';
					}
				}else{
					if(ww==2){
						src1 += tt;
					}else{
						src1 += '<a title="'+ss+''+getholiday+'" id="__'+this.eid+'_td_'+ss+'" href="javascript:void(0);">'+tt+'</a>';
					}
				}
			}
		}



		src1 += '</td>';

        if ( ww == (this.start_day+6)%7 ) {
            src1 += "</tr>\n";                                  // 表示開始曜日の１つ手前で行末
        }

    }
    src1 += '<tr><td colspan="3" class="prev"><a id="__'+this.eid+'_btn_prev" title="前の月へ" href="javascript:void(0)">&laquo;前の月へ</a></td>';
    src1 += '<td colspan="4" class="next"><a id="__'+this.eid+'_btn_next" title="次の月へ" href="javascript:void(0)">次の月へ&raquo;</a></td>';
    src1 += "</table>\n";
	src1 += "<p><small>日付をクリックすると、日付が自動で入力されます。</small></p>\n";
    src1 += '</div>\n';

    // カレンダーを書き換える
    var cal1 = this.getCalendarElement();
    if ( ! cal1 ) return;
    cal1.innerHTML = src1;

    // イベントを登録する
    var __this = this;
    var get_src = function (ev) {
        ev  = ev || window.event;
        var src = ev.target || ev.srcElement;
        return src;
    };
    var day_onmouseout = function (ev) {
        var src = get_src(ev);
// 2006.11.30 MOM 当月かつ今日日付であれば、今日日付用の背景色を適用
        var today = new Date();
        if( today.getMonth() == __this.date.getMonth() && src.id == '__'+__this.eid+'_td_'+__this.getDateYMD(today) ){
            src.style.background = __this.style.today_bgcolor;
        }else{
            src.style.background = __this.style.day_bgcolor;
        }
    };
    var day_onclick = function (ev) {
        var src = get_src(ev);
        var srcday = src.id.substr(src.id.length-10);
        __this.setFormValue( srcday );
        __this.fadeOut( 1.0 );
    };

//
// 2006.12.04 ksuzu 選択できない月へのリンクは作成しない
//
    // 前の月へボタン
    var tdprev = document.getElementById( "__"+this.eid+"_btn_prev" );
    //前の月の最終日
    var tmpDate = new Date(year,mon,1);
    tmpDate.setTime( tmpDate.getTime() - (24*3600*1000) );
    //選択可能な日がある？
    if ( !min || this.min_date <= tmpDate ){
        this.addEvent( tdprev, "click", function(){ __this.moveMonth( -1 ); });
    }
    //選択不可能
    else{
        tdprev.title = "前の月は選択できません";
    }

//
// 2006.12.04 ksuzu 表示月をクリックすると現在の月に移動
//
    var nMov = (realdd.getFullYear() - year) * 12 + (realdd.getMonth() - mon);
    if ( nMov != 0 ){
        // 現在の月へボタン
        var tdtoday = document.getElementById( "__"+this.eid+"_btn_today" );
        tdtoday.style.cursor = this.style.cursor;
        tdtoday.title = "現在の月へ";
        this.addEvent( tdtoday, "click", function(){ __this.moveMonth( nMov ); });
    }

    // 閉じるボタン
    var tdclose = document.getElementById( "__"+this.eid+"_btn_close" );

//
// 2006.12.04 ksuzu カレンダーの初期表示を戻す
//
    this.addEvent( tdclose, "click", function(){ __this.getFormValue(); __this.hide(); });

//
// 2006.12.04 ksuzu 選択できない月へのリンクは作成しない
//
    // 次の月へボタン
    var tdnext = document.getElementById( "__"+this.eid+"_btn_next" );
    //次の月の初日
    var tmpDate = new Date(year,mon,1);
    tmpDate.setTime( tmpDate.getTime() + (24*3600*1000)*32 );
    tmpDate.setDate(1);
    //選択可能な日がある？
    if ( !max || this.max_date >= tmpDate ){
        this.addEvent( tdnext, "click", function(){ __this.moveMonth( +1 ); });
    }
    //選択不可能
    else{
        tdnext.title = "次の月は選択できません";
    }

    // セルごとのイベントを登録する
    for ( var i=0; i<list.length; i++ ) {
        var dd = list[i];
        if ( mon != dd.getMonth() ) continue;       // 今月のセルにのみ設定する

        var utc = dd.getTime();
        if ( min && min > utc ) continue;// 昔過ぎる
        if ( max && max < utc ) continue;// 未来過ぎる
        if ( utc == curutc ) continue;// フォーム上の当日
        if ( !this.selectable_days[dd.getDay()] ) continue;// 2006.11.30 MOM 選択可能な曜日指定対応
        var ss = this.getDateYMD(dd);
        var cc = document.getElementById( "__"+this.eid+"_td_"+ss );
        if ( ! cc ) continue;
        this.addEvent( cc, "click", day_onclick );
    }

    // 表示する
    this.show();
};

// 旧バージョン互換（typo）
JKL.Calendar.prototype.getCalenderElement = JKL.Calendar.prototype.getCalendarElement;
JKL.Calender = JKL.Calendar;

