
var Calendar = {
    EVENT_MODE : "event",
    MONTH_MODE : "month",
    WEEK_MODE : "week",
    DAY_MODE : "day",

    sourceTypes : ["local", "remote", "attachment"],

    /**
     * The web app's context path.
     */
    contextPath : "",

    contentId : 0,

    calendars : new Object(),

    getCalendar : function(calendarId)
    {
        var cal = Calendar.calendars[calendarId];
        if (!cal)
        {
            cal = {
                calendarId : calendarId,
                loadingCount : 0,
                workingCount : 0,

                loadingPanel : $("calendar-loading-" + calendarId),
                displayPanel : $("calendar-display-" + calendarId),
                infoPanel : $("calendar-info-" + calendarId),
                listPanel : $("calendar-list-" + calendarId),

                detailsPanel : $("calendar-details-" + calendarId),
                detailsHeading : $('calendar-details-heading-' + calendarId),
                detailsErrors : $('calendar-details-errors-' + calendarId),
                detailsContent : $('calendar-details-content-' + calendarId),

                getDisplayMode : function()
                {
                    if (!this.displayMode)
                    {
                        this.displayMode = this.displayPanel.getAttribute("defaultView");
                        if (!this.displayMode)
                            this.displayMode = Calendar.MONTH_MODE;
                    }
                    return this.displayMode;
                },

                setDisplayMode : function(mode)
                {
                    this.displayMode = mode;
                },

                showSourceType : function(type)
                {
                    var typeSpan;
                    for (var i = 0; i < Calendar.sourceTypes.length; i++)
                    {
                        var aType = Calendar.sourceTypes[i];
                        typeSpan = $('calendar-ical-event-' + aType + '-' + this.calendarId);
                        if (typeSpan)
                        {
                            typeSpan.style.display = (type == aType) ? "inline" : "none";
                        }
                    }
                },

                getFirstDay : function() {
                    if (!this.firstDay)
                    {
                        this.firstDay = parseInt(this.displayPanel.getAttribute("firstDay"));
                    }
                    return this.firstDay;
                },

                getDisplayDate : function()
                {
                    if (!this.displayDate) // Set it to today in UTC
                    {
                        this.displayDate = this.getTodayUTC();
                    }

                    return this.displayDate;
                },

                getTodayUTC : function()
                {
                    var localNow = new Date();
                    localNow.setUTCDate(localNow.getDate());
                    return localNow;
                },

                setDisplayDate : function(date)
                {
//debug("setDisplayDate: " + date);
                    var oldDate = this.displayDate;
                    this.displayDate = date;

                    // update the date on the calendar, if it is visible
                    if (oldDate != null)
                    {
                        var oldDay = $('day-'+ this.calendarId + '-' + oldDate.getTime());
                        if (oldDay != null)
                            if (oldDay.className.indexOf(" selected") > -1) // assumes that selected is the last css class listed
                                oldDay.className = oldDay.className.substr(0, oldDay.className.length-9);
                    }

                    if (date != null)
                    {
                        var newDay = $('day-' + this.calendarId + '-' + date.getTime());
                        if (newDay != null)
                            newDay.className = newDay.className + " selected";
                    }
                },

                toDateId : function(date)
                {
                    var dateId = date.getTime();
                },

                setDisplayYear : function(year)
                {
                    this.getDisplayDate().setUTCFullYear(year);
                    this.refreshDisplay();
                    return false;
                },

                getDisplayYear : function()
                {
                    return this.getDisplayDate().getUTCFullYear();
                },

                setDisplayMonth : function(month)
                {
                    this.getDisplayDate().setUTCMonth(month-1);
                    this.refreshDisplay();
                    return false;
                },

                getDisplayMonth : function()
                {
                    return this.getDisplayDate().getUTCMonth() + 1;
                },

                setDisplayDay : function(day)
                {
                    this.getDisplayDate().setUTCDate(day);
                    this.refreshDisplay();
                    return false;
                },

                getDisplayDay : function()
                {
                    return this.getDisplayDate().getUTCDate();
                },

                setDisplayWeek : function(weekSelect, yearSelect)
                {
                    this.displayWeekNum = weekSelect.options[weekSelect.selectedIndex].value;
                    this.displayWeekYear = yearSelect.options[yearSelect.selectedIndex].value;
                    this.refreshDisplay();
                    this.displayWeekNum = null;
                    this.displayWeekYear = null;
                    return false;
                },

                getDisplayWeekNum : function() {
                    return this.displayWeekNum;
                },

                getDisplayWeekYear : function() {
                    return this.displayWeekYear;
                },
                
                makeToggleParams: function(subCalendarId) {
                    return {
                        "pageId" : Calendar.contentId,
                        "calendarId" : this.calendarId,
                        "subCalendarId" : subCalendarId,
                        "mode" : this.getDisplayMode(),
                        "year" : this.getDisplayYear(),
                        "month" : this.getDisplayMonth(),
                        "day" : this.getDisplayDay(),
                        "weekNum" : this.getDisplayWeekNum(),
                        "weekYear" : this.getDisplayWeekYear(),
                        "firstDay" : this.getFirstDay()
                    };
                },               

                makeDisplayParams : function() {
                    return {
                        "pageId" : Calendar.contentId,
                        "calendarId" : this.calendarId,
                        "mode" : this.getDisplayMode(),
                        "year" : this.getDisplayYear(),
                        "month" : this.getDisplayMonth(),
                        "day" : this.getDisplayDay(),
                        "weekNum" : this.getDisplayWeekNum(),
                        "weekYear" : this.getDisplayWeekYear(),
                        "firstDay" : this.getFirstDay()
                    };
                },

                eventDisplay : function() {
                    this.setDisplayMode(Calendar.EVENT_MODE);
                    this.refreshDisplay();
                    return false;
                },

                monthDisplay : function() {
                    this.setDisplayMode(Calendar.MONTH_MODE);
                    this.refreshDisplay();
                    return false;
                },

                weekDisplay : function() {
                    this.setDisplayMode(Calendar.WEEK_MODE);
                    this.refreshDisplay();
                    return false;
                },

                dayDisplay : function() {
                    this.setDisplayMode(Calendar.DAY_MODE);
                    this.refreshDisplay();
                    return false;
                },

                refreshDisplay : function()
                {
                    var uri = "/plugins/calendar/displayCalendar.action";
                    var params = this.makeDisplayParams();
                    return this.sendRequest(uri, params);
                },

                todayDisplay : function() {
                    this.setDisplayDate(this.getTodayUTC());
                    this.refreshDisplay();
                    return false;
                },

                /**
                 * Updates the main display to the next period. What that is depends on the current
                 * mode of the calendar.
                 *
                 * @see #setDisplayMode(mode)
                 */
                nextDisplay : function()
                {
                    var uri = "/plugins/calendar/displayCalendar!next.action";
                    var params = this.makeDisplayParams();
                    return this.sendRequest(uri, params);
                },

                prevDisplay : function()
                {
                    var uri = "/plugins/calendar/displayCalendar!prev.action";
                    var params = this.makeDisplayParams();
                    return this.sendRequest(uri, params);
                },

                toggleCalendar : function(subCalendarId)
                {
                    var uri = "/plugins/calendar/displayCalendar!toggle.action";
                    var params = this.makeToggleParams(subCalendarId);
                    return this.sendRequest(uri, params);
                },

                /* Calendar methods */

                makeSubCalParams : function(subCalendarId)
                {
                    return {
                        "pageId" : Calendar.contentId,
                        "calendarId" : this.calendarId,
                        "subCalendarId" : subCalendarId
                    };
                },

                refreshList : function() {
                    var uri = "/plugins/calendar/listCalendars.action";
                    var params = this.makeSubCalParams();
                    return this.sendRequest(uri, params);
                },

                addCalendar : function() {
                    var uri = "/plugins/calendar/addCalendar.action";
                    var params = this.makeSubCalParams();
                    return this.sendRequest(uri, params, true);
                },

                addCalendarForEvent : function() {
                    var uri = "/plugins/calendar/addCalendarForEvent.action";
                    var params = this.makeSubCalParams();
                    return this.sendRequest(uri, params, true);
                },

                viewCalendar : function(subCalendarId) {
                    var uri = "/plugins/calendar/viewCalendar.action";
                    var params = this.makeSubCalParams(subCalendarId);
                    return this.sendRequest(uri, params, true);
                },
               
                editCalendar : function(subCalendarId) {
                    var uri = "/plugins/calendar/editCalendar.action";
                    var params = this.makeSubCalParams(subCalendarId);
                    return this.sendRequest(uri, params, true);
                },

                deleteCalendar : function(subCalendarId) {
                    if (!confirm("This will delete this calendar permanently.\nAre you sure you wish to continue?"))
                        return false;
                    var uri = "/plugins/calendar/deleteCalendar.action";
                    var params = this.makeSubCalParams(subCalendarId);
                    return this.sendRequest(uri, params, true);
                },

                importCalendar : function(subCalendarId) {
                    var uri = "/plugins/calendar/ical/importCalendar.action";
                    var params = this.makeSubCalParams(subCalendarId);
                    return this.sendRequest(uri, params, true);
                },


                /* Update methods */
                updateDisplayContent : function(content)
                {
                    this.displayPanel.innerHTML = content;
                },

                updateDetailsContent : function(heading, content)
                {
                    this.detailsErrors.style.display = "none";
                    this.detailsHeading.innerHTML = heading;
                    this.detailsContent.innerHTML = content;
                    this.detailsPanel.style.display = "";
                },

                updateListContent : function(content)
                {
                    this.listPanel.innerHTML = content;
                },

                clearDetails : function() {
                    this.detailsPanel.style.display = "none";
                    this.detailsContent.innerHTML = "";
                    return false;
                },

                showError : function(message) {
                    alert(message);
                },

                showMessage : function(message) {
                    alert(message);
                },

                /* Event methods */

                makeEventParams : function(subCalendarId, eventId, date, allOccurrences, editMode)
                {
                    var year, month, day;

                    if (date)
                    {
                        year = date.getUTCFullYear();
                        month = date.getUTCMonth() + 1;
                        day = date.getUTCDate();
                    }
					
					if (!allOccurrences) 
					{
						allOccurrences = true;
					} 
					
					if (!editMode)
					{
					    editMode = false;
					}
					
                    return {
                        "pageId" : Calendar.contentId,
                        "calendarId" : this.calendarId,
                        "subCalendarId" : subCalendarId,
                        "startYear" : year,
                        "startMonth" : month,
                        "startDay" : day,
                        "eventId" : eventId,
                        "allOccurrences" : allOccurrences,
                        "editMode" : editMode
                    };
                },

                viewEvent : function(subCalendarId, eventId)
                {
                    var params = this.makeEventParams(subCalendarId, eventId);
                    var uri = "/plugins/calendar/viewEvent.action";
                    return this.sendRequest(uri, params, true);
                },

                addEvent : function(subCalendarId, date)
                {
                    if (!date)
                        date = this.getDisplayDate();

                    var params = this.makeEventParams(subCalendarId, null, date);
                    var uri = "/plugins/calendar/addEvent.action";
                    return this.sendRequest(uri, params, true);
                },

                editEvent : function(subCalendarId, eventId, allOccurrences)
                {
                    var params = this.makeEventParams(subCalendarId, eventId, null, allOccurrences, true);
                    var uri = "/plugins/calendar/editEvent.action";
                    return this.sendRequest(uri, params, true);
                },

                deleteEvent : function(subCalendarId, eventId, allOccurrences)
                {
                    if (!confirm("This will delete the event permanently\nDo you wish to continue?"))
                        return false;

                    var params = this.makeEventParams(subCalendarId, eventId, null, allOccurrences);

                    var uri = "/plugins/calendar/deleteEvent.action";

                    return this.sendRequest(uri, params, true);
                },

                showAddEvent : function(date) {
                    if (this.visibleAddEvent != null)
                        this.hideAddEvent();

                    this.visibleAddEvent = $('add-' + this.calendarId + '-' + date.getTime());
                    if (this.visibleAddEvent)
                        this.visibleAddEvent.className = "addEventVisible";
                },

                hideAddEvent : function(date) {
                    if (this.visibleAddEvent)
                    {
                        this.visibleAddEvent.className = "addEventHidden";
                        this.visibleAddEvent = null;
                    }
                },

                sendRequest : function(uri, params, clearDetails)
                {
                    var calendar = this;

                    if (clearDetails)
                    {
                        calendar.clearDetails();
                        calendar.showLoading(true);
                    }
                    else
                    {
                        calendar.showWorking(true);
                    }

                    if (uri.charAt(0) == "/")
                        uri = Calendar.contextPath + uri;

                    var sparams = this.serializeParams(params);

                    var callback =
                    {
                        method : "post",

                        parameters : sparams,

                        onComplete: function(data)
                        {
                            debug("sendRequest: response received");
                            if (data.status == 200)
                            {
                                //panelElem.innerHTML = data.responseText;
                                calendar.handleResponse(data.responseXML);
                            }
                            else
                            {
                                calendar.showAjaxError(data);
                            }

                            if (clearDetails)
                                calendar.showLoading(false);
                            else
                                calendar.showWorking(false);
                        },

                        onFailure : function(data, object) {
                            debug("sendRequest: failure");

                            calendar.showError("The operation failed.");

                            if (clearDetails)
                                calendar.showLoading(false);
                            else
                                calendar.showWorking(false);
                        },

                        onException : function(data, exception) {
                            debug("sendRequest: exception");

                            calendar.showError("The operation failed: " + exception.getMessage());

                            if (clearDetails)
                                calendar.showLoading(false);
                            else
                                calendar.showWorking(false);
                        }
                    }

                    debug("sendRequest: requesting '" + uri + "?" + sparams + "'");

                    // Send request to server
                    var req = new Ajax.Request(uri, callback);
                    return false;
                },

                showAjaxError : function(data) {
                    var message = "An error occurred while processing. Please contact an administrator.";
                    switch (data.status)
                    {
                    case 500:
                        message = "There was an error on the server. Please check your server logs for details.";
                        break;
                    case 404:
                        message = "The URL for the requested action does not exist.";
                        break;
                    }
                    this.showError(message);
                    debug("Ajax.Request.onComplete: " + data.status + " error:<br/>" + data.responseText);
                },

                /**
                 * @param uri The main body of the URI.
                 * @param params The set of parameters to attach to the URI.
                 */
                serializeParams : function(params)
                {
                    var key, value;
                    var first = true;
                    var uri = "";

                    for (key in params)
                    {
                        var type = typeof(params[key]);
                        if (params[key] != null && type != "function" && type != "undefined")
                        {
                            if (first)
                                first = false
                            else
                                uri += "&";
                            value = params[key];

            //debug("buildUri: key = '" + key + "'; value = '" + value + "'; type = " + typeof(params[key]));

                            uri += encodeURIComponent(key) + "=" + encodeURIComponent(value);
                        }
                    }

                    return uri;
                },

                submitForm : function(form)
                {
                    this.showLoading(true);

                    var params = Form.serialize(form);
                    if (params.indexOf("pageId=") == -1)
                        params += "&pageId=" + Calendar.contentId;
                    if (params.indexOf("calendarId=") == -1)
                        params += "&calendarId=" + this.calendarId;

                    var calendar = this;

                    var callback =
                    {
                        parameters : params,

                        onComplete: function(data)
                        {
                            if (data.status == 200)
                            {
                                calendar.handleResponse(data.responseXML);
                            }
                            else
                            {
                                calendar.showAjaxError(data);
                            }
                            calendar.showLoading(false);
                        }
                    }

                    debug("submitForm: requesting '" + form.action + "?" + params + "'");

                    // Send request to server
                    var req = new Ajax.Request(form.action, callback);
                    return false;
                },

                handleResponse : function(responseXML)
                {
                    if (!responseXML)
                        return alert("The action did not return the expected result.");
                    var response = responseXML.documentElement;

            //debug("handleResponse: response", response, 3);
            //debug("handleResponse: calendarId", calendarId);

                    var children = response.childNodes;
                    for (var i = 0; i < children.length; i++)
                    {
                        var exec = children[i];
                        if (exec.nodeName == "call")
                            this.execCall(exec);
                    }
                    return false;
                },

                execCall : function(callXML)
                {
                    calendar = this;

                    var call = "calendar." + callXML.getAttribute("method");
                    call += "(";

                    var paramNodes = callXML.getElementsByTagName("param");
                    var params = new Array();
                    for (var i = 0; i < paramNodes.length; i++)
                    {
                        if (i != 0)
                            call += ", ";

                        var param = paramNodes[i];


                        var type = param.getAttribute("type");
                        var value = this.getTextContent(param);
                        if (type == "date")
                            params[i] = new Date(parseInt(value));
                        else if (type == "integer")
                            params[i] = parseInt(value);
                        else if (type == "boolean")
                            params[i] = (value.toLowerCase() == "true" || value.toLowerCase() == "yes");
                        else
                            params[i] = value;

            //debug("execCall: params[" + i + "]", params[i]);

                        call += "params[" + i + "]";
                    }

                    call += ")";

            debug("execCall: call", call);

                    try
                    {
                        eval(call);
                    }
                    catch (e)
                    {
                        this.showMessage(typeof(e) == "object" ? e.description : e);
                    }
                },

                getTextContent : function(element) {
                    var children = element.childNodes;
                    var content = "";
                    for (var i = 0; i < children.length; i++)
                    {
                        var child = children[i];
//debug("getTextContent: nodeName = '" + child.nodeName);
                        if (child.nodeName == "#text" || child.nodeName == "#cdata-section")
                        {
                            content += child.data;
                        }
                    }
                    return content;
                },

                showWorking : function(show)
                {
                    var workingPanel = $("calendar-working-" + this.calendarId);
                    if (show)
                        this.workingCount += 1;
                    else
                        this.workingCount -= 1;

                    if (this.workingCount >= 1)
                    {
                        workingPanel.className = "displayWorking";
                   }
                    else
                    {
                        workingPanel.className = "displayWorkingIdle";
                    }
                },

                showLoading : function(show)
                {
                    if (show)
                        this.loadingCount += 1;
                    else
                        this.loadingCount -= 1;

                    if (this.loadingCount >= 1)
                    {
                        this.loadingPanel.className = "calendarLoading";
                    }
                    else
                    {
                        this.loadingPanel.className = "calendarLoadingIdle";
                    }
                }

            };
            Calendar.calendars[calendarId] = cal;
        }
        return cal;
    }
};

/**
 * A convenience function for retrieving calendars.
 */
function $C(calendarId) {
    return Calendar.getCalendar(calendarId);
}

// Try getting the context path from the global context path. May not work in all circumstances.
Calendar.contextPath = contextPath;