Tapestry.DateField = Class.create();

Tapestry.DateField.prototype = {

    // Initializes a DateField from a JSON specification.

    initialize : function(spec)
    {
        var i;
    
        this.field = $(spec.field);
        this.trigger = $(spec.field + ":trigger");
        
        this.showRedWeekDay = $(spec.showRedWeekDay);
        this.firstWeekDay = $(spec.firstWeekDay);
        
        this.submitOnSelectDate = $(spec.submitOnSelectDate);

        var dse = $(spec.dateStart);
        if (dse != null) {
            this.dateStart = new Date(dse[0], dse[1], dse[2]);
        } else this.dateStart = null;
        
        var dee = $(spec.dateEnd);
        if (dee != null) {
            this.dateEnd = new Date(dee[0], dee[1], dee[2]);
        } else this.dateEnd = null;

        this.excludeDays = $(spec.excludeDays);
        
        this.excludeDates = [];
        var eds = $(spec.excludeDates);
        for (i=0; eds != null && ((i+2) < eds.length); i+=3)
        {
            this.excludeDates[i/3] = new Date(eds[i], eds[i+1], eds[i+2]);
            //alert((i/3)+" > "+this.excludeDates[i/3]);
        }
        
        this.includeDates = [];
        var ids = $(spec.includeDates);
        for (i=0; ids != null && ((i+2) < ids.length); i+=3)
        {
            this.includeDates[i/3] = new Date(ids[i], ids[i+1], ids[i+2]);
            //alert((i/3)+" > "+this.includeDates[i/3]);
        }
        

        DatePicker.days = $(spec.weekDayAbbreviations);
        DatePicker.months = $(spec.monthNames);

        // i18n        
        DatePicker.messages = $(spec.messages);
        
        this.df_day_month_year = $(spec.df_day_month_year);
        
        this.trigger.observe("click", this.triggerClicked.bind(this));

        this.popup = null;
        
        this.field.observe("focus", this.triggerFocus.bind(this));
        
    },
    
    triggerFocus : function()
    {
        if (this.field.value == null || this.field.value.length < 1) {
            if (this.df_day_month_year) this.field.value = "dd/mm/yyyy";
            else this.field.value = "mm/dd/yyyy";
            this.field.select();
        }
    },

    triggerClicked : function()
    {
        if (this.field.disabled) return;

        if (this.popup == null)
        {
            this.createPopup();

        }
        else
        {
            if (this.popup.visible())
            {
                this.hidePopup();
                return;
            }
        }


        var value = $F(this.field);

        if (value == "")
        {
            this.datePicker.setDate(null);
        }
        else
        {

            // TODO: This is limited and americanized (not localized) to MM/DD/YYYY
            var re = /^\s*(\d+)\/(\d+)\/(\d{2,4})\s*$/;
            var matches = re.exec(value);

            // If the RE is bad, raise the date picker anyway, showing
            // the last valid date, or showing no date.

            if (matches != null)
            {

                var day, month, year;
                if (this.df_day_month_year) {
                    day = Number(matches[1])
                    month = Number(matches[2]);
                    year = Number(matches[3]);
                }
                else {
                    month = Number(matches[1]);
                    day = Number(matches[2])
                    year = Number(matches[3]);
                }
                

            // For two digits, guestamate which century they want.

                if (year < 100)
                {
                    if (year >= 60) year += 1900
                    else year += 2000;
                }

                var date = new Date(value);

                date.setMonth(month - 1);
                date.setDate(day);
                date.setFullYear(year);

                this.datePicker.setDate(date);
            }
        }

        this.positionPopup();

        this.revealPopup();
    },

    createPopup : function()
    {
        this.datePicker = new DatePicker();
        
        if (! this.showRedWeekDay) this.datePicker.setRedWeekDay(-1);
        
        this.datePicker.setFirstWeekDay(this.firstWeekDay);
        
        this.datePicker.setExcludeDays(this.excludeDays);
        this.datePicker.setExcludeDates(this.excludeDates);
        this.datePicker.setIncludeDates(this.includeDates);
        
        this.datePicker.setDateStart(this.dateStart);
        this.datePicker.setDateEnd(this.dateEnd);

        this.popup = $(this.datePicker.create());

        this.field.insert({ after : this.popup });

        this.popup.absolutize().hide();

        this.datePicker.onselect = function()
        {
            this.field.value = this.formatDate(this.datePicker.getDate());

            this.hidePopup();
            if (this.submitOnSelectDate) this.field.form.submit();

            //new Effect.Highlight(this.field);

        }.bind(this);
    },

    formatDate : function(date)
    {
        if (date == null) return "";

        if (this.df_day_month_year) return date.getDate() + "/" + (date.getMonth()+1) + "/" + date.getFullYear();
        else return (date.getMonth() + 1) + "/" + date.getDate() + "/" + date.getFullYear();
    },

    positionPopup : function()
    {
        this.popup.clonePosition(this.field, { offsetTop: this.field.getHeight() + 2 }).setStyle({ width: "", height: "" });
    },

    /** Duration used when fading the popup in or out. */

    FADE_DURATION : .20,

    hidePopup : function()
    {
        new Effect.Fade(this.popup, { duration: this.FADE_DURATION });
    },

    revealPopup : function()
    {

        // Only show one DateField popup at a time.

        if (Tapestry.DateField.activeDateField != undefined &&
            Tapestry.DateField.activeDateField != this)
        {
            Tapestry.DateField.activeDateField.hidePopup();
        }

        new Effect.Appear(this.popup, { duration: this.FADE_DURATION });

        Tapestry.DateField.activeDateField = this;
    }
};
