var cal;
function showCalendar(btn, y, m, d, url) {
    if (!cal) {
        cal = new Calendar(btn, y, m, d, url);
    }
    if (cal.showing) {
        cal.close();
    }
    cal.show(btn, y, m, d);
}

var Calendar = Class.create();
Calendar.prototype = {
    //////// 初期化 //////////////////////////////////////////////////
    //====== initialize ==============================
    initialize: function(btn, selectYear, selectMonth, selectDay, holidayXml) {
        this.button = btn;
	    this.selectYear = $(selectYear);
	    this.selectMonth = $(selectMonth);
	    this.selectDay = $(selectDay);
        this.calendar = $('calendar');
        this.create();
        this.isDragging = false;
        this.isShowing = false;
	    this.weekTbl = new Array("sun", "mon", "tue", "wed", "thu", "fri", "sat");
	    
	    this.marginLeft = -88;
	    this.marginTop = 5;
    
	    this.holidayXml = holidayXml;
        this.requestXml();
    }
    //====== エレメント生成 ==============================
    ,create: function() {
	    this.calendar.style.width = "250px";
    	
	    //--------------------------------------------------
	    this.headerPnl = document.createElement("div");
	    this.headerPnl.setAttribute('id', 'c_header');
	    this.headerPnl.style.cursor = "move";
	    this.calendar.appendChild(this.headerPnl);
    	 
        Event.observe(this.headerPnl, "mousedown", this.beginDrag.bindAsEventListener(this), false);
        Event.observe(document, "mousemove", this.dragging.bindAsEventListener(this), false);
        Event.observe(document, "mouseup", this.endDrag.bindAsEventListener(this), false);
    	
	    this.headerText = document.createElement("div");
	    this.headerText.setAttribute('id', 'ch_text');
	    this.headerPnl.appendChild(this.headerText);
    	
	    //--------------------------------------------------
	    this.headerCtrl = document.createElement("ul");
	    this.headerCtrl.setAttribute('id', 'ch_ctrl');
	    this.calendar.appendChild(this.headerCtrl);
    	
	    var li = document.createElement("li");
	    this.headerCtrl.appendChild(li);
	    var prevYear = document.createElement("input");
	    prevYear.type = "button";
	    prevYear.setAttribute('id', 'chc_prevyear');
	    prevYear.value = "<<";
	    prevYear.onclick = this.prevYear.bindAsEventListener(this);
	    li.appendChild(prevYear);

	    var li = document.createElement("li");
	    this.headerCtrl.appendChild(li);
	    var prevMonth = document.createElement("input");
	    prevMonth.setAttribute('id', 'chc_prevmonth');
	    prevMonth.type = "button";
	    prevMonth.value = "＜";
	    prevMonth.onclick = this.prevMonth.bindAsEventListener(this);
	    li.appendChild(prevMonth);

	    li = document.createElement("li");
	    this.headerCtrl.appendChild(li);
	    var thisMonth = document.createElement("input");
	    thisMonth.setAttribute('id', 'chc_thismonth');
	    thisMonth.type = "button";
	    thisMonth.value = "■";
	    thisMonth.onclick = this.thisMonth.bindAsEventListener(this);
	    li.appendChild(thisMonth);
    	
	    var li = document.createElement("li");
	    this.headerCtrl.appendChild(li);
	    var nextMonth = document.createElement("input");
	    nextMonth.setAttribute('id', 'chc_nextmonth');
	    nextMonth.type = "button";
	    nextMonth.value = "＞";
	    nextMonth.onclick = this.nextMonth.bindAsEventListener(this);
	    li.appendChild(nextMonth);
    	
	    var li = document.createElement("li");
	    this.headerCtrl.appendChild(li);
	    var nextYear = document.createElement("input");
	    nextYear.setAttribute('id', 'chc_nextyear');
	    nextYear.type = "button";
	    nextYear.value = ">>";
	    nextYear.onclick = this.nextYear.bindAsEventListener(this);
	    li.appendChild(nextYear);
    	
	    //--------------------------------------------------
	    this.bodyPnl = document.createElement("div");
	    this.bodyPnl.setAttribute('id', 'c_body');
	    this.calendar.appendChild(this.bodyPnl);
    	
	    //--------------------------------------------------
	    this.footerPnl = document.createElement("div");
	    this.footerPnl.setAttribute('id', 'c_footer');
	    this.calendar.appendChild(this.footerPnl);

	    this.footerCtrl = document.createElement("ul");
	    this.footerCtrl.setAttribute('id', 'cf_ctrl');
	    this.footerPnl.appendChild(this.footerCtrl);

	    var li = document.createElement("li");
	    this.footerCtrl.appendChild(li);
	    var close = document.createElement("input");
	    close.setAttribute('id', 'cfc_close');
	    close.type = "button";
	    close.value = "閉じる";
	    close.onclick = this.close.bindAsEventListener(this);
	    li.appendChild(close);
    }
    ,getSelectDate: function() {
	    y = parseInt(this.selectYear.options[this.selectYear.selectedIndex].value);
	    m = parseInt(this.selectMonth.options[this.selectMonth.selectedIndex].value) - 1;
	    d = parseInt(this.selectDay.options[this.selectDay.selectedIndex].value);
        return new Date(y, m, d);
    }
    //////// XML //////////////////////////////////////////////////
    ,requestXml : function() {
        this.loaded = false;
        var myAjax = new Ajax.Request(
            this.holidayXml,
            {
	            method: 'get'
	            ,onSuccess: this.analizeXml.bindAsEventListener(this)
	            ,onFailure: this.failed.bindAsEventListener(this)
            });
    }
    //====== XMLの解析 ==============================
    ,analizeXml : function(originalRequest) {
        var xmlDoc = originalRequest.responseXML.documentElement;
        this.holidays = new Holidays();
        this.holidays.loadXml(xmlDoc);
        this.loaded = true;
        this.show(this.button, this.selectYear.getAttribute('id'), this.selectMonth.getAttribute('id'), this.selectDay.getAttribute('id'));
    }
    //====== XMLの解析 ==============================
    ,failed: function() {
        //alert("failed");
        this.show(this.button, this.selectYear.getAttribute('id'), this.selectMonth.getAttribute('id'), this.selectDay.getAttribute('id'));
    }
    //////// 操作 //////////////////////////////////////////////////
    ,show: function(btn, selectYear, selectMonth, selectDay) {
        this.button = btn;
	    this.selectYear = $(selectYear);
	    this.selectMonth = $(selectMonth);
	    this.selectDay = $(selectDay);

        var pos = Position.cumulativeOffset(this.button);
        this.calendar.style.left = pos[0] + this.marginLeft + "px";
        this.calendar.style.top = pos[1] + Element.getHeight(this.button) + this.marginTop + "px";

        this.selectDate = this.getSelectDate();
        this.calendar.style.display = "block";
        this.showing = true;
        this.setCalendar(this.selectDate);
    }
    //====== 任意の年月を表示 ==============================
    ,setCalendar: function(date) {
        this.selectDate = date;
	    $('ch_text').innerHTML = this.selectDate.getFullYear() + "/" + (this.selectDate.getMonth() + 1);
    	
	    var today = new Date();
	    var thisYear = this.selectDate.getFullYear();
	    var thisMonth = this.selectDate.getMonth();
	    preDays = new Date(thisYear, thisMonth, 1).getDay();
	    sufDays = (7 - new Date(thisYear, thisMonth + 1, 1).getDay()) % 7;
	    days = new Date(thisYear, thisMonth + 1, 0).getDate();
	    len = preDays + days + sufDays;

	    var text = "<table>";

	    text += "<thead>";
	    text += "<tr>";
	    text += '<td class="sun">sun</td>';
	    text += '<td class="mon">mon</td>';
	    text += '<td class="tue">tue</td>';
	    text += '<td class="wed">wed</td>';
	    text += '<td class="thu">thu</td>';
	    text += '<td class="fri">fri</td>';
	    text += '<td class="sat">sat</td>';
	    text += "</tr>";
	    text += "</thead>";
    	
	    weekTbl = new Array("sun", "mon", "tue", "wed", "thu", "fri", "sat");
	    for (var i = 0; i < len; i++) {
	        if (i % 7 == 0) {
	            text += "<tr>";
	        }

            if (i >= preDays && i < preDays + days) {
                var state = 0;
                //本日判定
                if (thisYear == today.getFullYear() && thisMonth == today.getMonth() && (i - preDays + 1) == today.getDate()) {
                    state = 2;
                }
                //休日判定（走査量軽減のため、年で小分け）
                else if (this.loaded) {
                    for (var j = 0; j < this.holidays.holidayYears.length; j++) {
                        var holidayYear = this.holidays.holidayYears[j];
                        if (thisYear == holidayYear.year) {
                            for(var k = 0; k < holidayYear.holidays.length; k++) {
                                var holiday = holidayYear.holidays[k];
                                var d = holiday.date;
                                if (thisYear == d.getFullYear()) {
                                    if (thisMonth == d.getMonth()) {
                                        if ((i - preDays + 1) == d.getDate()) {
                                            state = 1;
                                            break;
                                        }
                                    }
                                }
                            }
                        }
	                    else if (thisYear < holidayYear.year) {
	                        break;
	                    }
                    }
                }
                
                text += '<td class="'
                switch (state) {
                    case 1:
                        text += "holiday";
                        break;
                        
                    case 2:
                        text += "today";
                        break;
                        
                    default:
        	            text += weekTbl[i % 7];
                        break;
                }
                text += '"';
	            text += ' onmouseover="cal.mouseover(this);"' +
	                ' onmouseout="cal.mouseout(this);"' +
	                ' onclick="cal.dayclick(' + (i - preDays + 1) + ');"' +
	                '>';
                text += ((i + 1) - preDays);
            }
            else {
	            text += '<td class="' + weekTbl[i % 7] + '">';
                text += "&nbsp;";
            }

            text += '</td>';
	        if (i % 7 == 6) {
	            text += "</tr>";
	        }
	    }
	    text += "</table>";
	    this.bodyPnl.innerHTML = text;
        }
    //====== カレンダーを閉じる ==============================
    ,close: function() {
        this.calendar.style.display = "none";
        this.showing = false;
    }
    //====== 前年 ==============================
    ,prevYear: function() {
        this.setCalendar(new Date(this.selectDate.getFullYear() - 1, this.selectDate.getMonth(), this.selectDate.getDate()));
    }
    //====== 来年 ==============================
    ,nextYear: function() {
        this.setCalendar(new Date(this.selectDate.getFullYear() + 1, this.selectDate.getMonth(), this.selectDate.getDate()));
    }
    //====== 今月 ==============================
    ,thisMonth: function() {
        d = new Date();
        this.setCalendar(new Date(d.getFullYear(), d.getMonth(), d.getDate()));
    }
    //====== 前月 ==============================
    ,prevMonth: function() {
        this.setCalendar(new Date(this.selectDate.getFullYear(), this.selectDate.getMonth() - 1, this.selectDate.getDate()));
    }
    //====== 次月 ==============================
    ,nextMonth: function() {
        this.setCalendar(new Date(this.selectDate.getFullYear(), this.selectDate.getMonth() + 1, this.selectDate.getDate()));
    }
    //====== カレンダーの日付にマウスオーバー ==============================
    ,mouseover: function(obj) {
        obj.style.fontWeight = "bold";
        obj.backgroundColor = obj.style.backgroundColor;
        obj.style.backgroundColor = "#ffffcc";
    }
    //====== カレンダーの日付からマウスアウト ==============================
    ,mouseout: function(obj) {
        obj.style.fontWeight = "normal";
        obj.style.backgroundColor = obj.backgroundColor;
    }
    //====== カレンダーの日付クリック ==============================
    ,dayclick: function(d) {
        y = this.selectDate.getFullYear();
        for (var i = 0; i < this.selectYear.options.length; i++) {
            if (this.selectYear.options[i].value == y) {
                this.selectYear.selectedIndex = i;
                break;
            }
        }
        this.selectMonth.selectedIndex = this.selectDate.getMonth();
        this.selectDay.selectedIndex = d - 1;
    }
    //////// ドラッグ //////////////////////////////////////////////////
    //====== 開始 ==============================
    ,beginDrag: function(event) {
        if (this.isDragging) {return;}

        this.isDragging = true;

        this.dragX = Event.pointerX(event) - parseInt(parseInt(this.calendar.style.left));
        this.dragY = Event.pointerY(event) - parseInt(this.calendar.style.top);

        this.headerPnl.setAttribute('unselectable', 'on');
        this.headerText.setAttribute('unselectable', 'on');
        return false;
    }
    //====== ドラッグ ==============================
    ,dragging: function(event) {
        if (!this.isDragging) {return;}

        this.calendar.style.left = Event.pointerX(event) - this.dragX + "px";
        this.calendar.style.top = Event.pointerY(event) - this.dragY + "px";
        return false;
    }
    //====== 終了 ==============================
    ,endDrag: function(event) {
        if (!this.isDragging) {return;}

        this.isDragging = false;

        this.headerPnl.removeAttribute('unselectable');
        this.headerText.removeAttribute('unselectable');
        return false;
    }

}

var Holidays = Class.create();
Holidays.prototype = {
    initialize: function() {
        this.holidayYears = new Array();
    }
    ,loadXml: function(node) {
        //====== 子読取 ========
        for (var n = node.firstChild; n; n = n.nextSibling) {
            if (n.nodeType == 1) {
                var holidayYear = new HolidayYear();
                holidayYear.loadXml(n);
                this.holidayYears.push(holidayYear);
            }
        }
    }
}
var HolidayYear = Class.create();
HolidayYear.prototype = {
    initialize: function() {
        this.holidays = new Array();
    }
    ,loadXml: function(node) {
        this.year = node.getAttribute('year');

        //====== 子読取 ========
        for (var n = node.firstChild; n; n = n.nextSibling) {
            if (n.nodeType == 1) {
                var holiday = new Holiday();
                holiday.loadXml(n);
                this.holidays.push(holiday);
            }
        }
    }
}
var Holiday = Class.create();
Holiday.prototype = {
    initialize: function() {
        this.date = 0;
        this.name = "";
    }
    ,loadXml: function(node) {
        var d = node.getAttribute('date');
        if (d) {
            var s = d.split('-');
            this.date = new Date(parseInt(s[0]), parseInt(s[1]) - 1, parseInt(s[2]));
        }
        
        this.name = node.getAttribute('name');
    }
}
