﻿/* AP.Calendar 
debugger*/
var AP
if (!AP)
    var AP = new Object();

AP.CalendarControl = new Object();

// highlightes all elements identified by name and gets source code from specified property
AP.CalendarControl.DropDown = function(items) {
    this.items = items;
    this.dropDown = document.createElement("SELECT");
    this.visible = false;

    this.CreateDropDown();
}

AP.CalendarControl.DropDown.prototype.CreateDropDown = function() {
    var option = document.createElement("OPTION");

    option.value = -1;
    option.innerHTML = "...";
    this.dropDown.appendChild(option);

    for (var i = 0; i < this.items.length; i++) {
        option = document.createElement("OPTION");

        option.value = i;
        option.innerHTML = this.items[i];
        this.dropDown.appendChild(option);
    }
}

var _days = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];
var _months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

// highlightes all elements identified by name and gets source code from specified property
AP.CalendarControl.Calendar = function(clicker, textBoxId, initialDate, /*optional*/fade, onClick) {
    this.clicker = clicker;
    this.date = isNaN(initialDate) ? new Date() : initialDate;
    this.textBoxId = textBoxId;
    this.span = document.createElement("SPAN");
    this.visible = false;
    this.fade = fade;
    this.onClick = onClick || Prototype.emptyFunction;
    if (this.fade == null)
        this.fade = true;

    this.monthSpan = null;
    this.yearSpan = null;
    this.monthDDL = new AP.CalendarControl.DropDown(_months);
    this.monthDDL.dropDown.onchange = function() {
        if (this.options[this.selectedIndex].value != -1) {
            var cal = this.parentNode.parentNode.parentNode.parentNode.Calendar;

            cal.ShowHideMonth();
            cal.date.setMonth(this.options[this.selectedIndex].value);
            cal.RePaint();
        }
    }
    this.yearTextBox = document.createElement("INPUT");
    this.yearTextBox.visible = false;
    this.yearTextBox.type = "text";
    this.yearTextBox.size = "5";
    this.yearTextBox.maxLength = "4";
    this.yearTextBox.onkeypress = function() {
        if (window.event.keyCode == 13) {
            Event.stop(event);
            if (isNaN(this.value)) {
                alert("Please enter a 4 digit year - only numbers");
            }
            else if (this.value.length != 4) {
                alert("Please enter a 4 digit year");
                return;
            }
            else {
                // valid!
                var cal = this.parentNode.parentNode.parentNode.parentNode.Calendar;

                cal.ShowHideYear();
                cal.date.setYear(this.value);
                cal.RePaint();
            }
        }
    };

    this.CreateCalendar();
}

AP.CalendarControl.Calendar.prototype.CreateCalendar = function() {
    var calTable = document.createElement("TABLE");

    this.span.className = "calendarWindow";
    this.span.appendChild(calTable);

    calTable.className = "calendar";
    calTable.Calendar = this;
    calTable.cellSpacing = "1";
    calTable.cellPading = "0";
    calTable.border = "0";

    this.AddInfoRow(calTable);
    this.AddNavigationRow(calTable);
    this.AddCalendar(calTable);
}


AP.CalendarControl.Calendar.prototype.AddInfoRow = function(table) {
    var cell = null;
    var row = table.insertRow(-1);

    // insert close row
    cell = row.insertCell(-1);
    cell.className = "header";
    cell.colSpan = "7";
    var today = document.createElement("A");
    today.innerHTML = "Today";
    Event.observe(today, "click", function() { this.ChangeDate(new Date()); } .bind(this));
    var help = document.createElement("A");
    help.innerHTML = "Help";
    var close = document.createElement("A");
    close.innerHTML = "Close";
    Event.observe(close, "click", this.ShowHide.bind(this));
    cell.appendChild(today);
    cell.appendChild(help);
    cell.appendChild(close);

    // insert description row
    row = table.insertRow(-1);
    row.style.display = "none";
    cell = row.insertCell(-1);
    cell.className = "help";
    cell.colSpan = "7";
    cell.innerHTML = "Navigate using the arrows or by clicking the month or year to manually change the date.";

    Event.observe(help, "click", function() { Element.toggle(row); });
}


AP.CalendarControl.Calendar.prototype.AddNavigationRow = function(table) {
    var cell = null;
    var row = table.insertRow(-1);

    // insert navigation row 
    row.className = "navigationHeader";

    cell = row.insertCell(-1);
    cell.innerHTML = "&lt;&lt;";
    cell.className = "selectable";
    cell.title = "Go to previous year";
    Event.observe(cell, "click", this.PrevYear.bind(this));
    cell = row.insertCell(-1);
    cell.innerHTML = "&lt;";
    cell.className = "selectable";
    cell.title = "Go to previous month";
    Event.observe(cell, "click", this.PrevMonth.bind(this));

    cell = row.insertCell(-1);
    cell.colSpan = "3";
    cell.align = "center";
    this.monthSpan = document.createElement("SPAN");
    this.yearSpan = document.createElement("SPAN");
    this.monthSpan.className = "selectable";
    this.yearSpan.className = "selectable";
    Event.observe(this.monthSpan, "click", this.ShowHideMonth.bind(this));
    Event.observe(this.yearSpan, "click", this.ShowHideYear.bind(this));
    this.monthSpan.innerHTML = _months[this.date.getMonth()] + " ";
    this.yearSpan.innerHTML = this.date.getFullYear();
    cell.appendChild(this.monthSpan);
    cell.appendChild(this.yearSpan);

    cell = row.insertCell(-1);
    cell.innerHTML = "&gt;";
    cell.className = "selectable";
    cell.title = "Go to next month";
    Event.observe(cell, "click", this.NextMonth.bind(this));
    cell = row.insertCell(-1);
    cell.innerHTML = "&gt;&gt;";
    cell.className = "selectable";
    cell.title = "Go to next year";
    Event.observe(cell, "click", this.NextYear.bind(this));
}


AP.CalendarControl.Calendar.prototype.AddCalendar = function(table) {
    var prevMaxDate = this.MonthMaxDate(this.date, -1);
    var thisMaxDate = this.MonthMaxDate(this.date, 0);
    var cell = null;
    var row = table.insertRow(-1);
    var self = this;
    row.className = "dayHeader";

    // create day headers
    for (var i = 0; i < _days.length; i++) {
        cell = row.insertCell(-1);
        cell.innerHTML = _days[i];
    }

    // create actual calendar of days
    var d = new Date(this.date.getFullYear(), this.date.getMonth(), 1);
    var pastMonth = 0;
    var startDay = d.getDay(); // add one to this if you ALWAYS want a few (possibly 7) days the next month to follow this month.
    for (i = 0; i < Math.ceil((thisMaxDate + startDay) / 7) * 7; i++) {
        // create a new row every 7 days
        if (i % 7 == 0)
            row = table.insertRow(-1);
        cell = row.insertCell(-1);

        // if previous month
        if (i < d.getDay()) {
            var day = prevMaxDate - d.getDay() + i + 1;
            cell.className = "otherMonth";
            cell.innerHTML = day;
            //cell.onclick = new Function("AP.CalendarControl.SelectDay(" + d.getFullYear() + ", " + (d.getMonth() - 1) + ", " + day + ", '" + this.textBoxId + "', '" + this.clicker.id + "');");
            cell.date = new Date(d);
            cell.day = day;
            Event.observe(cell, "click", function() {
                self.SelectDay(this.date.getFullYear(), this.date.getMonth() - 1, this.day);
            } .bind(cell));
        }
        // if current month
        else if (pastMonth == 0) {
            cell.innerHTML = d.getDate();
            cell.className = "selectable";
            if (new Date().format("MDYYYY") == d.format("MDYYYY"))
                cell.className += " today";

            if (this.fade) {
                cell.onmouseover = function() { AP.CalendarControl.Fade(this, "highlight", 0, 34, 75); }
                cell.onmouseout = function() { AP.CalendarControl.Fade(this, "highlight", 100, -34, 75); }
            }
            else {
                cell.onmouseover = function() { Element.addClassName(this, "highlight"); }
                cell.onmouseout = function() { Element.removeClassName(this, "highlight"); }
            }
            //cell.onclick = new Function("AP.CalendarControl.SelectDay(" + d.getFullYear() + ", " + d.getMonth() + ", " + d.getDate() + ", '" + this.textBoxId + "', '" + this.clicker.id + "');");
            cell.date = new Date(d);
            Event.observe(cell, "click", function() {
                self.SelectDay(this.date.getFullYear(), this.date.getMonth(), this.date.getDate());
            } .bind(cell));

            d.setDate(d.getDate() + 1);
            //if the date loops back to the 1st then we are in the next month
            if (d.getDate() == 1)
                pastMonth = 1;
        }
        //if next month
        else {
            cell.className = "otherMonth";
            cell.innerHTML = pastMonth;
            //cell.onclick = new Function("AP.CalendarControl.SelectDay(" + d.getFullYear() + ", " + d.getMonth() + ", " + pastMonth + ", '" + this.textBoxId + "', '" + this.clicker.id + "');");
            cell.date = new Date(d);
            cell.pastMonth = pastMonth;
            Event.observe(cell, "click", function() {
                self.SelectDay(this.date.getFullYear(), this.date.getMonth(), this.pastMonth);
            } .bind(cell));
            pastMonth++;
        }
    }
}

AP.CalendarControl.Calendar.prototype.MonthMaxDate = function(currDate, offset) {
    var newMaxDate = 31;
    var newMonth = currDate.getMonth() + offset;
    var newYear = currDate.getFullYear();

    if (offset > 0 && newMonth == 0)
        newYear++;
    else if (offset < 0 && newMonth == 11)
        newYear--;

    var newDate = new Date(newYear, newMonth, newMaxDate);

    while (newMaxDate != newDate.getDate()) {
        newMaxDate--;
        newDate.setMonth(newMonth);
        newDate.setDate(newMaxDate);
    }
    return newMaxDate;
}

AP.CalendarControl.Calendar.prototype.PrevYear = function() {
    this.ChangeYear(-1);
}

AP.CalendarControl.Calendar.prototype.NextYear = function() {
    this.ChangeYear(1);
}

AP.CalendarControl.Calendar.prototype.PrevMonth = function() {
    this.ChangeMonth(-1);
}

AP.CalendarControl.Calendar.prototype.NextMonth = function() {
    this.ChangeMonth(1);
}

AP.CalendarControl.Calendar.prototype.ChangeDate = function(date) {
    if (isNaN(date))
        return;

    this.date = date;
    this.RePaint();
}

AP.CalendarControl.Calendar.prototype.ChangeYear = function(change) {
    this.date.setYear(this.date.getFullYear() + change);

    this.RePaint();
}

AP.CalendarControl.Calendar.prototype.ChangeMonth = function(change) {
    var nextMonth = this.date.getMonth() + change;
    var nextYear = this.date.getFullYear();

    if (change > 0 && nextMonth == 0)
        nextYear++;
    else if (change < 0 && nextMonth == 11)
        nextYear--;

    this.date.setYear(nextYear);
    this.date.setMonth(nextMonth);

    this.RePaint();
}

AP.CalendarControl.Calendar.prototype.ShowHideYear = function() {
    if (!this.yearTextBox.visible) {
        this.yearSpan.parentNode.insertBefore(this.yearTextBox, this.yearSpan.nextSibling);
        this.yearTextBox.focus();
        this.yearTextBox.select();
    }
    else
        this.yearSpan.parentNode.removeChild(this.yearTextBox);

    this.yearTextBox.visible = !this.yearTextBox.visible;
}

AP.CalendarControl.Calendar.prototype.ShowHideMonth = function() {
    if (!this.monthDDL.visible)
        this.monthSpan.parentNode.insertBefore(this.monthDDL.dropDown, this.monthSpan.nextSibling);
    else
        this.monthSpan.parentNode.removeChild(this.monthDDL.dropDown);

    this.monthDDL.visible = !this.monthDDL.visible;
}

AP.CalendarControl.Calendar.prototype.RePaint = function() {
    // we must hide this calendar, otherwise when it is created
    // ...various items in tables will be formatted *as they appear/are created*
    // ...in the document by IE.  We do not want this formatting to
    // ...occur until everythign has been completley created
    this.ShowHide();

    this.span.innerHTML = "";
    this.CreateCalendar();

    this.ShowHide();
}

AP.CalendarControl.Calendar.prototype.GetControler = function() {
    return this.clicker;
}

AP.CalendarControl.Calendar.prototype.ShowHide = function() {
    if (!this.visible) {
        this.clicker.parentNode.insertBefore(this.span, this.clicker.nextSibling);
        EnsureOpake(this.span);
    }
    else {
        RemoveOpake(this.span);
        this.clicker.parentNode.removeChild(this.span);
    }

    this.visible = !this.visible;
}

AP.CalendarControl.Calendar.prototype.SelectDay = function(year, month, day) {
    var d = new Date(year, month, day);

    $(this.textBoxId).value = (d.getMonth() + 1) + "/" + d.getDate() + "/" + d.getFullYear();
    this.onClick(this, d);
}


var _calendars = new Array();

AP.CalendarControl.ShowHideCalendar = function(clicker, textBoxId, date, fade, onClick) {
    var cal = AP.CalendarControl.GetCalendar(clicker, textBoxId, date, fade, onClick);
    cal.ChangeDate(date);
    cal.ShowHide();
}

function ShowHideCal(clicker, txtId, delay) {
    var clicker = $(clicker);
    setTimeout(function() { AP.CalendarControl.ShowHideCalendar(clicker, txtId, new Date(), false, Cal_OnDateClick); } .bind(this), delay || 0);
}
function Cal_OnDateClick(sender, date) {
    sender.ShowHide();
}

//AP.CalendarControl.ChangeDate = function(clickerId, year, month, date) {
//  var clicker = $(clickerId);
//  
//  AP.CalendarControl.GetCalendar(clicker, null, null).ChangeDate(year, month, date);
//}

AP.CalendarControl.GetCalendar = function(clicker, textBoxId, date, fade, onClick) {
    var ret;

    for (var i = 0; i < _calendars.length; i++) {
        var cal = _calendars[i];
        if (cal.GetControler() == clicker)
            ret = cal;
        else
            if (cal.visible) cal.ShowHide();
    }
    if (ret) return ret;

    // did not find that object's calendar so create a new one and show it 
    _calendars[i] = new AP.CalendarControl.Calendar(clicker, textBoxId, date, fade, onClick);

    return _calendars[i];
}


AP.CalendarControl.Fade = function(that, className, opacityStart, change, interval) {
    if (that.fades == null) {
        that.fades = new Array();
        that.StartFades = AP.CalendarControl.StartFades;
        that.fades[that.fades.length] = function() { AP.CalendarControl.DoFade(that, className, opacityStart, change, interval); };
        that.fading = that.fades.length - 1;
        that.fades[that.fades.length - 1]();
    }
    else {
        that.fades[that.fades.length] = function() { AP.CalendarControl.DoFade(that, className, opacityStart, change, interval); };
        if (that.fading == -1) {
            that.fading = that.fades.length - 1;
            that.fades[that.fades.length - 1]();
        }
    }
}

AP.CalendarControl.DoFade = function(that, className, opacityStart, change, interval) {
    var newOpacity = opacityStart + change;

    // done
    if (newOpacity <= 0 || newOpacity >= 100) {
        if (change < 0)
            Element.removeClassName(that, className);
        that.style.removeAttribute("filter");

        //remove the fade we just completed/are compelting
        that.fades[that.fading] = null;
        for (var i = 0; i < that.fades.length; i++) {
            if (that.fades[i] != null) {
                that.fading = i;
                that.fades[i]();
                // we need to stop here becuase the fade we just called
                // will run this same for loop and take care of all the
                // the other fades.
                return;
            }
        }
        // if we get here we have processed all avaliable fades,
        // we are finally done, clean up and signal completion
        that.fades = null;
        that.fading = -1;
    }
    // still fading
    else {
        if (change > 0)
            Element.addClassName(that, className);
        that.style.filter = "alpha(opacity = " + newOpacity + ")";
        setTimeout(function() { AP.CalendarControl.DoFade(that, className, newOpacity, change, interval); }, interval);
    }
}

AP.CalendarControl.SelectDay = function(year, month, day, textBoxId) {
    var d = new Date(year, month, day);

    $(textBoxId).value = (d.getMonth() + 1) + "/" + d.getDate() + "/" + d.getFullYear();
}

