﻿//===================================================================
// 文件名:		CalendarWindow.js
// 版权:		Copyright (C) 2009 Elong
// 创建人:		zhi.Luo
// 创建日期:	2009-10-16
// 描述:		双栏日历弹出对话框，日期是否可选状态支持任意设置（通过isDisabledDay:function()）
// 备注:		
// 示例代码：
//                new CalendarWindow({
//                    eventElement: $(input),
//                    selectedDate: $(input).value,
//                    language: "en",
//                    enabledFrom: "2009-1-1",
//                    enabledTo: "2009-1-5",
//                    onSelected: function(date) {
//                        alert(date);
//                    } .bind(this)
//                });
//                new CalendarWindow({
//                    eventElement: $(input),
//                    selectedDate: $(input).value,
//                    isDisabledDay: function(year, month, day) {
//                        if (day == 5) return true; //每月5日不可选状态
//                    }.bind(this),
//                    onSelected: function(date) {
//                        alert(date);
//                    } .bind(this)
//                });
//===================================================================

var CalendarWindow = Elong.Control.CalendarWindow;
CalendarWindow = Class.create();

Object.extend(CalendarWindow.prototype, {
    name: "CalendarWindow",
    popRegion: new Template("<div class=\"com_cbox\" >  <div class=\"calendar_year\"><div class=\"year\"><a method=\"btnPre\" href=\"#?\" title=\"上一月\" class=\"mf_lr_a\">&nbsp;</a></div>#{MonthSPAN}	<div class=\"month_1\"><a  method=\"btnNext\" title=\"下一月\" href=\"#?\" class=\"mf_rr_a\">&nbsp;</a></div><div class=\"month\"><a method=\"close\" class=\"ac_close_t cur\" title=\"关闭\" href=\"#?\">x</a></div>  </div>  <div class=\"date_box\">	#{MonthHTML}	<div class=\"hr\"></div>	#{nextMonthHTML}  </div>  <div class=\"clear\"></div>  <div class=\"com_cbox_b com_cbox_lt\"></div>  <div class=\"com_cbox_b com_cbox_rt\"></div>  <div class=\"com_cbox_b com_cbox_lb\"></div>  <div class=\"com_cbox_b com_cbox_rb\"></div><div class=\"clear\"></div></div>"),
    weakHTML_cn: "<tr class=\"family\"><th>日</th><th>一</th><th>二</th><th>三</th><th>四</th><th>五</th><th>六</th></tr>",
    weakHTML_en: "<tr class=\"family\"><th>S</th><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th></tr>",
    monthSPAN_cn: "<span class=\"h\">{0}年{1}月</span><span class=\"m\">{2}年{3}月</span>",
    monthSPAN_en: "<span class=\"h\">{0}.{1}</span><span class=\"m\">{2}.{3}</span>",

    options: {
        eventElement: null,                     // 触发事件object
        selectedDate: null,                     // 显示已选中的日期"2009-01-01"，默认为今日
        language: "cn",                         // 中文: cn, en
        enabledFrom: null,                      // 设置可选日期开始时间："2009-01-01",默认为今日
        enabledTo: null,                        // 设置可选日期结束时间: "9999-12-12", 默认不限制
        onSelected: null                        // 用户选择后回调函数: onSelected(date),  date为yyyy/mm/dd或者mm/dd/yyyy
        // isDisabledDay判断是否是可选的日期派生方法:function(year, month, day)
    },

    //初始化
    initialize: function(options) {
        Object.extend(Object.extend(this, this.options), options);
        this.initializeDOM();
        this.initializeEvent();
        
        // 格式化初始参数
        if (Object.isNull(this.selectedDate) || String.isNullOrEmpty(this.selectedDate) || !this.validateDate(this.selectedDate)) { this.selectedDate = this.getTodayString(); }
        else { this.selectedDate = this.reFormatDateString(this.selectedDate); }
        this.startYear = parseInt(this.selectedDate.split("-")[0], 10);
        this.startMonth = parseInt(this.selectedDate.split("-")[1], 10);

        this.weakHTML = this.language.toLowerCase() == "cn" ? this.weakHTML_cn : this.weakHTML_en;

        this.refreshMonth(this.startYear, this.startMonth);
        this.render();
    },

    initializeDOM: function() {
        this.contentEndRegion = $("#m_contentend");
        this.windowElement = $("<div style=\"display:none; position: absolute; z-index: 2000;\"></div>").appendTo(this.contentEndRegion);
    },

    destroyDOM: function() {
        this.windowElement = null;
        this.contentEndRegion = null;
        this.options = null;
    },

    initializeEvent: function() {
        this.windowElement.bind("click", this.onClickRegion.bindAsEventListener(this));
        this.windowElement.bind("mouseout", this.onMouseOutRegion.bindAsEventListener(this));
        this.windowElement.bind("mouseover", this.onMouseOverRegion.bindAsEventListener(this));
        FunctionExt.defer(this.onOutClick.bindAsEventListener(this), 100);
    },

    destroyEvent: function() {
        this.windowElement.unbind("click");
        this.windowElement.unbind("mouseout");
        this.windowElement.unbind("mouseover");
    },

    onOutClick: function() {
        $(document).one("click", function(evt) {
            var element = Event.element(evt);
            if (this.windowElement.find("*").index(element) == -1 &&
                (element.attr("method") != "btnPre" && element.attr("method") != "btnNext")) { this.dispose(); }
        } .bindAsEventListener(this));
    },

    onClickRegion: function(evt) {
        var elem = Event.element(evt);
        var method = elem.attr("method");
        switch (method) {
            case "btnPre":
                if (this.startMonth < 3) { this.startYear--; }
                if (this.startMonth < 3) { this.startMonth += 12; }
                this.startMonth -= 2;
                this.refreshMonth(this.startYear, this.startMonth);
                return;
            case "btnNext":
                if (this.startMonth > 10) { this.startYear++; }
                if (this.startMonth > 10) { this.startMonth -= 12; }
                this.startMonth += 2;
                this.refreshMonth(this.startYear, this.startMonth);
                return;
            case "close":
                this.dispose();
                return;
        }

        if (elem.is("td") && !elem.hasClass("Close") && parseInt(elem.text(), 10) > 0) {
            if (!Object.isNull(this.onSelected)) {
                var dateStr = elem.parents("table").attr("date") + elem.text();
                this.onSelected(this.reFormatDateString(dateStr, this.language.toLowerCase() == "cn"));
            }
            this.dispose();
        }
    },

    onMouseOverRegion: function(evt) {
        var element = Event.element(evt);
        if (this.outTimer != null) {
            clearTimeout(this.outTimer);
            this.outTimer = null;
        }

        if (element.is("li")) { element.addClass("li_cur"); }
    },

    onMouseOutRegion: function(evt) {
        var element = Event.element(evt);
        this.outTimer = FunctionExt.defer(function() {
            this.dispose();
        }, 1000, this);

        if (element.is("li")) { element.removeClass("li_cur"); }
    },

    render: function() {
        // 设置大小位置
        var top = this.eventElement.offset().top + this.eventElement.height() + 6;
        var left = this.eventElement.offset().left;

        this.windowElement[0].style.top = top + "px";
        this.windowElement[0].style.left = left + "px";
        this.ie6FilterIFrame = Globals.addIE6Filter(this.windowElement.width(), this.windowElement.height(), left, top);
        this.windowElement.show();

    },

    refreshMonth: function(year, month) {
        var nextYear = month == 12 ? year + 1 : year;
        var nextMonth = month == 12 ? 1 : month + 1;
        var spanHTML = this.language.toLowerCase() == "cn" ? this.monthSPAN_cn : this.monthSPAN_en;
        spanHTML = String.format(spanHTML, year, month, nextYear, nextMonth);

        var contentHTML = this.popRegion.eval({
            MonthSPAN: spanHTML,
            MonthHTML: this.getDateHTML(year, month),
            nextMonthHTML: this.getDateHTML(nextYear, nextMonth)
        });

        this.windowElement.html(contentHTML);
    },


    isDisabledDay: function(year, month, day) {
        if (Object.isNull(this.enabledFrom)) { this.enabledFrom = this.getTodayString(); }

        var curr = year + "-" + month + "-" + day;
        return !this.validateDateRange(curr, this.enabledFrom, this.enabledTo);

        //        var arr = this.enabledFrom.split("-");
        //        if (year > parseInt(arr[0], 10)) return false;
        //        if (year == parseInt(arr[0], 10) && month > parseInt(arr[1], 10)) return false;
        //        if (year == parseInt(arr[0], 10) && month == parseInt(arr[1], 10) && day >= parseInt(arr[2], 10))
        //            return false;

        //        return true;
    },

    /*验证为正确的日期格式*/
    validateDate: function(value) {
        var iaMonthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
        var iaDate = new Array(3)
        var year, month, day

        var result = true;
        var strValue = value;
        if (strValue.length != 0) {
            iaDate = strValue.split("-")
            if (iaDate.length != 3 || iaDate[1].length > 2 || iaDate[2].length > 2 || iaDate[1].length < 1 || iaDate[2].length < 1) {
                result = false;
            }

            year = parseInt(iaDate[0], 10);
            month = parseInt(iaDate[1], 10);
            day = parseInt(iaDate[2], 10);

            if (isNaN(year) || isNaN(month) || isNaN(day)) {
                result = false;
            }

            if (year < 1900 || year > 2100) {
                result = false;
            }

            if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) iaMonthDays[1] = 29;
            if (month < 1 || month > 12 || day < 1 || day > iaMonthDays[month - 1]) {
                result = false;
            }
        }

        return result;
    },

    validateDateRange: function(value, minDate, maxDate) {
        if (Object.isNull(minDate)) { minDate = "0001-01-01"; }
        if (Object.isNull(maxDate)) { maxDate = "9999-12-31"; }

        return this.reFormatDateString(value) >= this.reFormatDateString(minDate) &&
            this.reFormatDateString(value) <= this.reFormatDateString(maxDate);
    },

    /*把日期字符串格式化成 yyyy-mm-dd格式 ，便于比较大小*/
    reFormatDateString: function(dateStr, isCn) {
        var dateArray = new Array(3);
        var year, month, day;

        if (dateStr.length == 0)
            return '';

        if (dateStr.indexOf("-") > -1) {
            dateArray = dateStr.split("-");
            if (dateArray.length != 3) { return ""; }
            year = dateArray[0];
            month = dateArray[1];
            day = dateArray[2];
        }
        else {
            dateArray = dateStr.split("/");
            if (dateArray.length != 3) { return ""; }
            year = dateArray[2];
            month = dateArray[0];
            day = dateArray[1];
        }

        if (year.length <= 2) year = '19' + year;
        if (month.length == 1) month = '0' + month;
        if (day.length == 1) day = '0' + day;
        return Object.isNull(isCn) || isCn ? year + '-' + month + '-' + day : month + '/' + day + "/" + year;
    },

    //每个月的日期数
    getDayCount: function(year, month) {
        var dayCount = 0;
        var days = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
        if (month == 0) {
            dayCount = 31;
        }
        else if (month == 2) {
            if ((year % 400 == 0) || (year % 4 == 0 && year % 100 > 0)) {
                dayCount = 29;  //闰年
            }
            else {
                dayCount = 28;
            }
        }
        else {
            dayCount = days[month - 1];
        }
        return dayCount;
    },

    //获取日期列表
    getDateHTML: function(year, month) {
        var li = "<td onmouseover=\"$(this).toggleClass('hover')\" onmouseout=\"$(this).toggleClass('hover')\" class=\"{1}\">{0}</td>";
        var disableLi = "<td class=\"Close\">{0}</td>";
        var grayLi = "<td onmouseover=\"$(this).toggleClass('hover')\" onmouseout=\"$(this).toggleClass('hover')\" class=\"{1}\">{0}</td>";
        var dateSb = new StringBuilder();
        dateSb.append(String.format("<table date=\"{0}-{1}-\" width=\"140\" height=\"115\" cellspacing=\"0\" cellpadding=\"0\">", year, month));
        dateSb.append(this.weakHTML);
        var dayCount = this.getDayCount(year, month);
        var firstDate = new Date(year, month - 1, 1);
        var beginDay = firstDate.getDay();         //1号是星期几：0-6
        var liStyle = "";
        var lineCount = 1;
        var count1 = dayCount + beginDay;
        var j = 1;
        for (var i = 0; i < count1; i++) {
            if (i % 7 == 0) { dateSb.append("<tr>") };
            if (this.isDisabledDay(year, month, j)) {
                liStyle = disableLi; // 不可选
            }
            else if (i % 7 == 0 || (i + 1) % 7 == 0) {
                liStyle = grayLi;
            }
            else {
                liStyle = li;
            }
            var className = "";
            var currday = this.reFormatDateString(year + "-" + month + "-" + j);
            if (currday == this.selectedDate) { className = "selected"; }
            if (currday == this.getTodayString()) { className = "newdate"; }

            if (i < beginDay) {
                dateSb.append(String.format(liStyle, "", className));
            }
            else {
                dateSb.append(String.format(liStyle, j, className));
                j++;
            }
            if (i % 7 == 6) { dateSb.append("</tr>"); }
        }
        var lastDate = new Date(year, month - 1, dayCount);
        var endDay = lastDate.getDay(); //最后一天是星期几
        var count2 = 6 - endDay;
        for (var i = 0; i < count2; i++) {
            if ((i + 1) % 7 != 0) {
                dateSb.append(String.format(li, ""));
            }
            else {
                dateSb.append(String.format(grayLi, ""));
            }
        }
        dateSb.append("</tr></table>");
        return dateSb.toString();
    },

    // 获得当前日期，用于比较
    getTodayString: function() {
        var d = new Date();
        return this.getDateString(d);
    },

    // 获取日期字符串2009-01-12
    getDateString: function(dateObj) {
        var month = dateObj.getMonth() + 1;
        var day = dateObj.getDate();
        var monthStr = month > 9 ? month.toString() : '0' + month.toString();
        var dayStr = day > 9 ? day.toString() : '0' + day.toString();
        var result = dateObj.getFullYear().toString() + '-' +
		monthStr + '-' + dayStr;
        return result;
    },

    dispose: function() {
        if (this.windowElement) {
            this.windowElement.fadeOut("normal");
            FunctionExt.defer(function() {
                if (this.windowElement) {
                    Globals.closeIE6Fliter(this.ie6FilterIFrame);
                    this.windowElement.remove();
                    this.destroyEvent();
                    this.destroyDOM();
                }
            } .bind(this), 500);
        }
    }
});
