var cal;

function showCalendar(objText)
{
    if (!cal) {
        cal = new Calendar();
    }
    cal.objText = objText;
    
    cal.showCalendar();
}

//**********************************************************************
//カレンダー
//**********************************************************************
var Calendar = Class.create();
Calendar.prototype = {
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //コンストラクタ
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    initialize: function() {
        //////// 定数 //////////////////////////////
        this.ONE_DAY = 24 * 60 * 60 * 1000;
        this.ONE_WEEK = this.ONE_DAY * 7;
        this.WEEK_TBL = new Array('日', '月', '火', '水', '木', '金', '土');
        this.CLS_TBL = new Array('sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat');

        //////// 初期化 //////////////////////////////
        this.objText = null;
        today = new Date();
        this.showDate = new Date(today.getFullYear(), today.getMonth(), 1);
        this.selDate = new Date(today.getFullYear(), today.getMonth(), today.getDate());
        this.dragging = false;

        //////// エレメント生成 //////////////////////////////
        this.createElement();

//        this.showNowLoadingPanel(true);
        //////// 休日マスタ読み込み //////////////////////////////
        this.holidayMst = new HolidayMst();
    }
    //////// エレメント生成 ////////////////////////////////////////
    ,createElement: function() {
        //////// 枠 //////////////////////////////
        el = document.createElement('div');
        el.className = 'calPanel';
        document.body.appendChild(el);
        this.calPanel = el;
        
        //////// ヘッダ //////////////////////////////
        el = document.createElement('div');
        this.calPanel.appendChild(el);
        el.className = 'calHeader';
        this.calHeader = el;
        Event.observe(this.calHeader, "mousedown", this.mousedown.bindAsEventListener(this), false);
        Event.observe(document, "mousemove", this.mousemove.bindAsEventListener(this), false);
        Event.observe(document, "mouseup", this.mouseup.bindAsEventListener(this), false);
        
        el = document.createElement('span');
        el.innerHTML = 'calendar header';
        this.calHeader.appendChild(el);
        this.headerText = el;
        
        el = document.createElement('input');
        el.setAttribute('type', 'button');
        el.setAttribute('value', '×');
        el.onclick = this.close.bindAsEventListener(this);
        this.calHeader.appendChild(el);
        this.closeButton = el;


        //////// メニュー //////////////////////////////
        //====== メニュー枠 ==============================
        el = document.createElement('div');
        el.className = 'calMenu';
        this.calPanel.appendChild(el);
        this.calMenu = el;

        table = document.createElement('table');
        this.calMenu.appendChild(table);
        
        tbody = document.createElement('tbody');
        table.appendChild(tbody);
        
        tr = document.createElement('tr');
        tbody.appendChild(tr);
        
        //前年
        td = document.createElement('td');
        td.className = 'menuPrevYear';
        tr.appendChild(td);

        a = document.createElement('a');
        a.innerHTML = '前年';
        a.href = 'javascript:;';
        a.onclick = this.prevYear.bindAsEventListener(this);
        td.appendChild(a);

        //前月
        td = document.createElement('td');
        td.className = 'menuPrevMonth';
        tr.appendChild(td);

        a = document.createElement('a');
        a.innerHTML = '前月';
        a.href = 'javascript:;';
        a.onclick = this.prevMonth.bindAsEventListener(this);
        td.appendChild(a);

        //今月
        td = document.createElement('td');
        td.className = 'menuThisYear';
        tr.appendChild(td);

        a = document.createElement('a');
        a.innerHTML = '今月';
        a.href = 'javascript:;';
        a.onclick = this.thisMonth.bindAsEventListener(this);
        td.appendChild(a);

        //翌月
        td = document.createElement('td');
        td.className = 'menuNextYear';
        tr.appendChild(td);

        a = document.createElement('a');
        a.innerHTML = '翌月';
        a.href = 'javascript:;';
        a.onclick = this.nextMonth.bindAsEventListener(this);
        td.appendChild(a);

        //翌年
        td = document.createElement('td');
        td.className = 'menuNextYear';
        tr.appendChild(td);

        a = document.createElement('a');
        a.innerHTML = '翌年';
        a.href = 'javascript:;';
        a.onclick = this.nextYear.bindAsEventListener(this);
        td.appendChild(a);

        //////// ボディ //////////////////////////////
        el = document.createElement('div');
        el.className = 'calBody';
        this.calPanel.appendChild(el);
        this.calBody = el;

        //====== 枠 ==============================
        el = document.createElement('table');
        this.calBody.appendChild(el);
        this.calendar = el;
        
        //====== ヘッダ ==============================
        thead = document.createElement('thead');
        this.calendar.appendChild(thead);
        
        tr = document.createElement('tr');
        thead.appendChild(tr);
        
        for (var i = 0; i < 7; i++) {
            td = document.createElement('td');
            td.className = this.CLS_TBL[i];
            td.innerHTML = this.WEEK_TBL[i];
            tr.appendChild(td);
        }
    }
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //表示
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //////// カレンダーを表示する ////////////////////////////////////////
    ,showCalendar: function()
    {
        this.calPanel.style.display = 'none';

        //////// テキストボックスの値を読み取ろうとする ////////
        if (this.objText) {
            str = this.objText.value;
            if (str.length > 0) {
                str.match(/([\d]{4,4})[\/\-]([\d]{1,2})[\/\-]([\d]{1,2})/);
                year = parseInt(RegExp.$1);
                month = parseInt(RegExp.$2) - 1;
                day = parseInt(RegExp.$3);
                if (year && month && day) {
                    this.selDate = new Date(year, month, day);
                    this.showDate = new Date(year, month, 1);
                }
            }
        }

        //////// カレンダーセット ////////
        this.setCalendar();
        
        //////// クライアント領域情報 ////////
        if (this.objText) {
            this.calPanel.style.left = parseInt(this.objText.offsetLeft) + 'px';
            this.calPanel.style.top = (parseInt(this.objText.offsetTop) + parseInt(this.objText.offsetHeight) + 1) + 'px';
        }
        
        this.calPanel.style.display = 'block';
    }
    //////// カレンダーを生成する ////////////////////////////////////////
    ,setCalendar:function()
    {
        //////// クリア //////////////////////////////
        if (this.tbody) {
            this.calendar.removeChild(this.tbody);
        }
        
        //////// ボディ //////////////////////////////
        tbody = document.createElement('tbody');
        this.calendar.appendChild(tbody);
        this.tbody = tbody;

        thisMonthFirst = this.showDate;
        nextMonthsFirst = new Date(this.showDate.getFullYear(), this.showDate.getMonth() + 1, 1);
        thisMonthLast = new Date();
        thisMonthLast.setTime(nextMonthsFirst.getTime() - this.ONE_DAY);

        preDayCount = thisMonthFirst.getDay();
        afterDayCount = (7 - nextMonthsFirst.getDay()) % 7;
        thisMonthDayCount = thisMonthLast.getDate();
        len = preDayCount + thisMonthDayCount + afterDayCount;

        d = new Date();
        today = new Date();
        today = new Date(today.getFullYear(), today.getMonth(), today.getDate());
        s = this.showDate.getTime();
        
        for (var i = 0; i < len; i++) {
            //======== 行の頭でtr追加 ========
            if (i % 7 == 0) {
                tr = document.createElement('tr');
                tbody.appendChild(tr);
            }
            
            //======== 行 ========
            td = document.createElement('td');

            d.setTime(s + this.ONE_DAY * (i - preDayCount));
            td.innerHTML = d.getDate();

            if (i < preDayCount) {
                //------ 前月 --------
                td.className = 'othermonth';
            }
            else if (i < preDayCount + thisMonthDayCount)
            {
                //------ 今月 --------
                td.className = this.CLS_TBL[i % 7];

                td.onmouseover = this.mouseover.bindAsEventListener(this, td);
                td.onmouseout = this.mouseout.bindAsEventListener(this, td);
                td.onclick = this.select.bindAsEventListener(this, d.getDate());
                
                if (d.getTime() == today.getTime()) {
                    //本日判定
                    td.className = 'today';
                }
                else if (d.getTime() == this.selDate.getTime()) {
                    //選択判定
                    td.className = 'selected';
                }
                else {
                    //休日
                    y = parseInt(d.getFullYear());
                    for (var j = 0; j < this.holidayMst.holidayYears.length; j++) {
                        HY = this.holidayMst.holidayYears[j];
                        if (HY.year == y) {
                            for (var k = 0; k < HY.holidays.length; k++) {
                                H = HY.holidays[k];
                                if (H.date.getTime() == d.getTime()) {
                                    td.className = 'holiday';
                                    td.title = H.name;
                                    break;
                                }
                            }
                            break;
                        }
                    }
                }
            }
            else {
                //------ 翌月 --------
                td.className = 'othermonth';
            }
            tr.appendChild(td);
        }

        //////// カレンダーヘッダ //////////////////////////////
        year = this.showDate.getFullYear();
        month = this.showDate.getMonth() + 1;
        this.headerText.innerHTML = year + '年' + month + '月';
    }
    ,mouseover: function(obj, td)
    {
        td.backgroundColor = td.style.backgroundColor;
        td.style.backgroundColor = '#ffff00';
    }
    ,mouseout: function(obj, td)
    {
        td.style.backgroundColor = td.backgroundColor;
        td.style.backgroundColor = undefined;
    }
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //メニュー系
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //////// 前年に移動 ////////////////////////////////////////
    ,prevYear: function()
    {
        this.showDate = new Date(this.showDate.getFullYear() - 1, this.showDate.getMonth(), 1);
        this.setCalendar();
    }
    //////// 前月に移動 ////////////////////////////////////////
    ,prevMonth: function()
    {
        this.showDate = new Date(this.showDate.getFullYear(), this.showDate.getMonth() - 1, 1);
        this.setCalendar();
    }
    //////// 今月に移動 ////////////////////////////////////////
    ,thisMonth: function()
    {
        today = new Date();
        this.showDate = new Date(today.getFullYear(), today.getMonth(), 1);
        this.setCalendar();
    }
    //////// 翌月に移動 ////////////////////////////////////////
    ,nextMonth: function()
    {
        this.showDate = new Date(this.showDate.getFullYear(), this.showDate.getMonth() + 1, 1);
        this.setCalendar();
    }
    //////// 翌年に移動 ////////////////////////////////////////
    ,nextYear: function()
    {
        this.showDate = new Date(this.showDate.getFullYear() + 1, this.showDate.getMonth(), 1);
        this.setCalendar();
    }
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //操作
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //////// 選択 ////////////////////////////////////////
    ,select: function(obj, date)
    {
        this.selDate = new Date(this.showDate.getFullYear(), this.showDate.getMonth(), date);
        if (this.objText) {
            this.objText.value = this.selDate.getFullYear() + '/' + (this.selDate.getMonth() + 1) + '/' + this.selDate.getDate();
        }
        this.close();
    }
    //////// 閉じる ////////////////////////////////////////
    ,close:function()
    {
        this.calPanel.style.display = 'none';
    }
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //ウィンドウ系
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    ,mousedown:function(e)
    {
        if (this.dragging){return;}
        this.dragging = true;
        body = document.getElementsByTagName('body').item(0);
        body.setAttribute('unselectable', 'on'); //文字選択禁止
        document.body.setAttribute('unselectable', 'on'); //文字選択禁止

        MX = Event.pointerX(e);
        MY = Event.pointerY(e);
        this.dragStartX = MX;
        this.dragStartY = MY;
        this.oldLeft = parseInt(this.calPanel.style.left);
        this.oldTop = parseInt(this.calPanel.style.top);
    }
    ,mousemove:function(e)
    {
        if (!this.dragging){return;}

        MX = Event.pointerX(e);
        MY = Event.pointerY(e);
        this.calPanel.style.left = this.oldLeft + (MX - this.dragStartX) + 'px';
        this.calPanel.style.top = this.oldTop + (MY - this.dragStartY) + 'px';
    }
    ,mouseup:function(e)
    {
        if (!this.dragging){return;}
        this.dragging = false;
        body = document.getElementsByTagName('body').item(0);
        body.removeAttribute('unselectable'); //文字選択禁止
        document.body.removeAttribute('unselectable'); //文字選択禁止

        MX = Event.pointerX(e);
        MY = Event.pointerY(e);
        this.calPanel.style.left = this.oldLeft + (MX - this.dragStartX) + 'px';
        this.calPanel.style.top = this.oldTop + (MY - this.dragStartY) + 'px';
    }
}

//**********************************************************************
//休日マスタ
//**********************************************************************
var HolidayMst = Class.create();
HolidayMst.prototype = {
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //コンストラクタ
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    initialize: function() {
        this.holidayYears = new Array();
        this.request();
    }
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //XML
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //////// リクエスト ////////////////////////////////////////
    ,request:function()
    {
        requestUrl = '../js/holidays.xml';
        var myAjax = new Ajax.Request(
            requestUrl,
            {
	            method: 'get'
	            ,onSuccess: this.success.bindAsEventListener(this)
	            ,onFailure: this.failed.bindAsEventListener(this)
            });
    }
    ,success:function(originalRequest)
    {
        var xmlDoc = originalRequest.responseXML.documentElement;
        this.loadXml(xmlDoc);
        this.loaded = true;
    }
    ,failed:function()
    {
        this.loaded = false;
        alert('failed');
    }
    //////// XMLロード ////////////////////////////////////////
    ,loadXml: function(node) {
        //====== 子読取 ========
        for (var n = node.firstChild; n; n = n.nextSibling) {
            if (n.nodeType == 1) {
                var holidayYear = new HolidayYear();
                if (holidayYear.loadXml(n)) {
                    this.holidayYears.push(holidayYear);
                }
            }
        }
    }
}
//**********************************************************************
//休日(年)
//**********************************************************************
var HolidayYear = Class.create();
HolidayYear.prototype = {
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //コンストラクタ
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    initialize: function() {
        this.year = 0;
        this.holidays = new Array();
    }
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //XML
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //////// XMLロード ////////////////////////////////////////
    ,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();
                if (holiday.loadXml(n)) {
                    this.holidays.push(holiday);
                }
            }
        }
        return true;
    }
}
//**********************************************************************
//休日
//**********************************************************************
var Holiday = Class.create();
Holiday.prototype = {
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //コンストラクタ
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    initialize: function() {
        this.date = 0;
        this.name = '';
    }
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //XML
    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //////// XMLロード ////////////////////////////////////////
    ,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');
        
        return true;
    }
}
