﻿
function initCalendar(el, options) {
    
    var defaults = {
        viewsAllowed: 'month,agendaWeek,list',  //ok
        displayTimeZone: 'True',  // not enabled
        fulltimescale: 'False', // ok
        listBeforeDays: '1', //ok
        listAfterDays: '5', //ok
        defaultView: 'month', //ok
        ModuleID: -1, //ok
        UserID: '-1',  //ok
        isAdmin: 'False',  //ok
        editURL: '',  //ok
        slotMinuts: '15',  //ok
        ddlCategoriesID: '',
        listshowHeader: 'Yes',
        listfields: 'BD;ED;EN',
        listShowNextN: 'False',
        displayothermonths: 'True'
    };
        
    var options = $.extend(defaults, options);

    obj = $(el);
    
    var _eventdetails = el.replace("calendar", "eventdetails");
    var _eventwrapper = el.replace("EventsPlus_calendar", "ModuleContent");
    var _eventcategories = el.replace("calendar", "pnlCategories");
    var _eventsiconbar = el.replace("calendar", "events_iconbar");
    var _eventsloading = el.replace("calendar", "eventsloading");
    var _initialized = false;

    // initialize the events details form
    $(_eventdetails).dialog({
        resizable: false,
        modal: true,
        autoOpen: false,
        width: 600
    });

    // assign listener to calendar select; bind new calendarr
    $('#' + options.ddlCategoriesID).change(function () {
        listView(obj.fullCalendar('getView'));
        obj.fullCalendar('refetchEvents');
        return false;
    });
        
    // init calendar
    obj.fullCalendar({
        slotMinutes: parseInt(options.slotMinutes),
        defaultView: options.defaultView,
        theme: true,
        weekMode: 'liquid',
        events: {
            url: '/desktopmodules/events/eventsplus/eventsplus.asmx/FetchCalendarByRange',
            type: 'POST',
            lazyLoading: false,
            cache: true,
            data: {
                moduleid: options.ModuleID
            }
        },
        loading: function (bool) {
            if (bool) { $(_eventsloading).show(); }
            else {
                $(_eventsloading).hide();
            }
        },
        header: {
            left: 'prev,next today',
            center: options.viewsAllowed,
            right: 'title'
        },
        eventClick: function (calEvent, jsEvent, view) {
            bindEventDetails(calEvent.id, options.ModuleID);
        },
        viewDisplay: function (view) {
            listView(view);
            if (_initialized == false) {
                $(_eventcategories).appendTo(obj.find('.fc-header-right'));

                $('<tr><td class="fc-header-top" colspan="3"></td></tr>').prependTo(obj.find('.fc-header > tbody:first'));
                $(obj.find('.fc-header-title')).prependTo(obj.find('.fc-header-top'));
                $(_eventsiconbar).appendTo(obj.find('.fc-header-top'));
                _initialized = true;
            }

            if (options.listshowHeader === 'No' && view.name == 'List') {
                obj.find('.fc-header-title').hide();
            } else {
                obj.find('.fc-header-title').show();
            }

            if (options.listShowNextN == 'True' && view.name == 'List') {
                obj.find('.fc-button-prev').hide();
                obj.find('.fc-button-next').hide();
                obj.find('.fc-button-today').hide();
            } else {
                obj.find('.fc-button-prev').show();
                obj.find('.fc-button-next').show();
                obj.find('.fc-button-today').show();
            }
        },
        minTime: ((options.fulltimescale == 'True') ? 0 : 6),
        maxTime: ((options.fulltimescale == 'True') ? 24 : 22),
        timeFormat: {
            agenda: 'h:mm{ - h:mm}',
            year: 'h:mm tt ddd M/d/yy',
            "": 'h:mm tt'
        },
        ListViewStart: options.listBeforeDays,
        ListViewEnd: options.listAfterDays,
        ddlCategoriesID: options.ddlCategoriesID,
        displayothermonths: options.displayothermonths
    });

    function listView(view) {
        if (view.name == 'List') {
            var category = $('#' + options.ddlCategoriesID).length > 0 ? $('#' + options.ddlCategoriesID).val() : "";
            var url, data;

            if (options.listShowNextN == 'False') {
                data = "{category: '" + category + "', endDate: '" + Math.round((new Date(view.visEnd)).getTime() / 1000) + "', moduleid: " + options.ModuleID + ", startDate: '" + Math.round((new Date(view.visStart)).getTime() / 1000) + "'}";
                url = '/desktopmodules/events/eventsplus/eventsplus.asmx/FetchCalendarByRange';
            } else {
                data = "{category: '" + category + "',  moduleid: " + options.ModuleID + "}";
                url = '/desktopmodules/events/eventsplus/eventsplus.asmx/FetchCalendarNEvents';
            }

            $.ajax({
                type: "POST",
                data: data,
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                url: url,
                success: function (events) {
                    $('.fc-view-list').empty().html('<div style="position: relative; -moz-user-select: none; display: block;" class="fc-view fc-view-list fc-grid" unselectable="on"><table cellspacing="0" style="width: 100%;" class="fc-border-separate"><thead><tr class="fc-first fc-last"><th class="fc-tue ui-widget-header fc-first fc-last">' + view.title + '</th></tr></thead><tbody><tr class="fc-first fc-last"><td class="fc-tue ui-widget-content fc-first fc-last ui-state-highlight"><div><div class="fc-day-content"></div></div></td></tr></tbody></table></div>');
                    if (events.d.length > 0) {
                        events.d.sort(function (a, b) { return parseDate(a.start) - parseDate(b.start) });
                        for (i = 0; i < events.d.length; i++) {
                            if ((parseDate(events.d[i].start) >= view.visStart && parseDate(events.d[i].start) < view.visEnd) || options.listShowNextN == 'True') {
                                $('.fc-view-list .fc-day-content').append(slotSegHtml(events.d[i], options));
                            }
                        }
                        $('.fc-view-list .fc-event').click(function (ev) {
                            bindEventDetails($(this).attr('rel'), options.ModuleID);
                        });
                    }

                    if ($('.fc-day-content').children().length < 1) {
                        $('.fc-view-list .fc-day-content').append("<div class='ui-state-highlight ui-corner-all'><p><span class='ui-icon ui-icon-info'></span> No events found!</p></div>");
                    }
                }
            });
        }
        else {
            $('.fc-button-list').removeClass('ui-state-active');
        }
    }

    function bindEventDetails(EventID, ModuleID) {
        $.ajax({
            type: "POST",
            url: "/desktopmodules/events/eventsplus/eventsplus.asmx/FetchEvent",
            data: "{EventID: " + EventID + ", ModuleID: " + options.ModuleID + "}",
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            success: function (msg) {
                bindField('#title', msg.d.EventName);

                if (msg.d.allDay === true) {
                    bindField('#start', htmlEscape(formatDate(parseDate(msg.d.start), 'ddd MMM dd')));
                    bindField('#end', htmlEscape(formatDate(parseDate(msg.d.end), 'ddd MMM dd')));
                    bindField('#duration', 'All Day Event');
                }
                else {
                    bindField('#start', htmlEscape(formatDate(parseDate(msg.d.start), 'ddd MMM dd - h:mm tt')));
                    bindField('#end', htmlEscape(formatDate(parseDate(msg.d.end), 'ddd MMM dd - h:mm tt')));
                    bindField('#duration', formatDuration(msg.d.Duration));
                }
                bindField('#category', msg.d.CategoryName);
                bindField('#location', msg.d.LocationName);

                if (msg.d.EventDesc != 'Enter event description') {
                    bindField('#description', htmlunescape(msg.d.EventDesc));                   
                }

                if (ModuleID != msg.d.ModuleID) {
                    bindLink('#sourcecalendartitle', msg.d.ModuleTitle, msg.d.ModuleURL);
                }

                $('.icons').empty();
                switch (msg.d.Importance) {
                    case 1:
                        bindIcon("ui-icon-alert", "Important");
                        bindField("#importance", "Important");
                        break;
                    case 2:
                        $(_eventdetails).find("#importance").parent().hide();
                        break;
                    case 3:
                        bindIcon("ui-icon-arrowthick-1-s", "Low Importance");
                        bindField("#importance", "Low Importance");
                        break;
                }

                if (msg.d.RRULE != '') bindIcon("ui-icon-calendar", "Recurring Event");

                if (msg.d.SendReminder = 'true') {
                    var ReminderTimeMeasurement
                    switch (msg.d.ReminderTimeMeasurement) {
                        case 'm':
                            ReminderTimeMeasurement = 'minutes';
                            break;
                        case 'h':
                            ReminderTimeMeasurement = 'hour(s)';
                            break;
                        case 'd':
                            ReminderTimeMeasurement = 'day(s)';
                            break;
                    }
                    bindIcon("ui-icon-clock", "Reminder will be sent " + msg.d.ReminderTime + " " + ReminderTimeMeasurement + " prior to event.");
                }

                var buttons = {
                    Close: function () { $(this).dialog('close'); }
                };

                // if admin, add edit button
                if (options.isAdmin == 'True') {
                    var reg = new RegExp("\\{" + 0 + "\\}", "gm");
                    buttons.Edit = function () {
                        window.location = options.editURL.replace(reg, msg.d.EventID);
                    };
                    if (msg.d.RRULE != '') {
                        $('.ui-dialog-buttonpane button:eq(2)').removeClass('ui-helper-hidden');
                        buttons['Edit Series'] = function () {
                            window.location = options.editURL.replace(reg, msg.d.EventID) + "&EditRecur=All";
                        };
                    } else {
                        $('.ui-dialog-buttonpane button:eq(2)').addClass('ui-helper-hidden');
                    }
                }

                $(_eventdetails).dialog("option", "title", msg.d.EventName).dialog("option", "buttons", buttons).dialog('open');
            }
        });
    }

    function bindField(el, val) {
        if (!(val == undefined || val === '')) { $(_eventdetails).find(el).html(val).parent().show(); } else { $(_eventdetails).find(el).parent().hide(); }
    }

    function bindIcon(cssclass, title) {
        $(_eventdetails + ' .icons').append('<span class="ui-icon ' + cssclass + '" title="' + title + '"></span>');
    }

    function bindLink(el, val, href) {
        if (!(val == undefined || val === '')) { $(_eventdetails).find(el).html(val).attr('href', href).parent().show(); } else { $(_eventdetails).find(el).parent().hide(); }
    }
}

//************ HELPER FUNCTION ***************//
function htmlEscape(s) {
    return s.replace(/&/g, '&amp;')
		.replace(/</g, '&lt;')
		.replace(/>/g, '&gt;')
		.replace(/'/g, '&#039;')
		.replace(/"/g, '&quot;')
		.replace(/\n/g, '<br />');
}

function getSkinCss(event, opt) {
    var source = event.source || {};
    var eventColor = event.color;
    var sourceColor = source.color;
    var backgroundColor =
		event.backgroundColor ||
		eventColor ||
		source.backgroundColor ||
		sourceColor; // ||
	var borderColor =
		event.borderColor ||
		eventColor ||
		source.borderColor ||
		sourceColor;// ||
	var textColor =
		event.textColor ||
		source.textColor;
	var statements = [];
    if (backgroundColor) {
        statements.push('background-color:' + backgroundColor);
    }
    if (borderColor) {
        statements.push('border-color:' + borderColor);
    }
    if (textColor) {
        statements.push('color:' + textColor);
    }
    return statements.join(';');
}

function slotSegHtml(event, options) {
    var t = this;
    var html = "<";
    var url = event.url;
    var skinCss = getSkinCss(event);
    var skinCssAttr = (skinCss ? " style='" + skinCss + "'" : '');
    var classes = ['fc-event', 'fc-event-skin', 'fc-event-vert', 'fc-corner-left', 'fc-corner-right'];
    var startend = '';
    classes = classes.concat(event.className);
    if (event.source) {
        classes = classes.concat(event.source.className || []);
    }
    if (url) {
        html += "a href='" + htmlEscape(event.url) + "'";
    } else {
        html += "div";
    }
   
    if (event.AllDayEvent == true) {
        startend = formatDate(parseDate(event.start), 'ddd MMM d');
        if (formatDate(parseDate(event.start), 'ddd d') != formatDate(parseDate(event.end), 'ddd d')) {
            startend += ' - ' + formatDate(parseDate(event.end), 'ddd MMM d');
        }
        startend += ' All Day Event'

    } else {
        if (options.listfields.indexOf('BD') > -1) {
            startend += htmlEscape(formatDate(parseDate(event.start), 'ddd MMM d @ h:mm tt'))
        }
        if (options.listfields.indexOf('ED') > -1) {
            if (formatDate(parseDate(event.start), 'ddd d') == formatDate(parseDate(event.end), 'ddd d')) {
                startend += ' - ' + formatDate(parseDate(event.end), 'h:mm tt');
            } else {
                startend += ' - ' + formatDate(parseDate(event.end), 'ddd MMM d @ h:mm tt');
            }
        }
        if (options.listfields.indexOf('DU') > -1) {
            startend += ' (' + formatDuration(event.Duration) + ')';
        }
    }

    html +=
			" class='" + classes.join(' ') + "'" +
			" style='margin-top: 4px;" + skinCss + "'" + " rel='" + event.EventID + "'" +
 			">" +
			"<div class='fc-event-inner fc-event-skin'" + skinCssAttr + ">" +
			"<div class='fc-event-head fc-event-skin'" + skinCssAttr + ">" +
			"<div class='fc-event-time'>" +
            startend +
         	"</div>" +
			"</div>" +
			"<div class='fc-event-content'>" 
			            
            if (options.listfields.indexOf('EN') > -1) {
                html += "<div class='fc-event-title'>" + htmlEscape(event.title) + "</div>";
            }

            if (options.listfields.indexOf('DE') > -1 && htmlDecode(event.EventDesc) != '') {
                html += "<div class='fc-event-description'>" + htmlDecode(event.EventDesc) + "</div>";
            }

            if (options.listfields.indexOf('CA') > -1 || options.listfields.indexOf('LO') > -1) {
                html += "<div class='fc-event-details'>";
            }

            if (options.listfields.indexOf('CA') > -1  && event.CategoryName != '') {
                html += "<span class='fc-event-category'>Category: " + htmlDecode(event.CategoryName) + "</span>";
            }

            if (options.listfields.indexOf('LO') > -1 && event.LocationName != '') {
                html += "<span class='fc-event-location'>Location: " + htmlDecode(event.LocationName) + "</span>";
            }

            if (options.listfields.indexOf('CA') > -1 || options.listfields.indexOf('LO') > -1) {
                html += "</div>";
            }
 
    html += "</div></div>"; // close inner
    html += "</" + (url ? "a" : "div") + ">";
    return html;
}

function htmlunescape(html) {
    var htmlNode = document.createElement('div');
    htmlNode.innerHTML = html;
    if (htmlNode.innerText) {
        return htmlNode.innerText; // IE
    }
    return htmlNode.textContent; // FF
}

function htmlEncode(value) {
    return $('<div/>').text(value).html();
}

function htmlDecode(value) {
    return $('<div/>').html(value).text();
}

function DateAdd(ItemType, DateToWorkOn, ValueToBeAdded) {
    switch (ItemType)
    {
        //date portion         
        case 'd': //add days
            DateToWorkOn.setDate(DateToWorkOn.getDate() + ValueToBeAdded)
            break;
        case 'm': //add months
            DateToWorkOn.setMonth(DateToWorkOn.getMonth() + ValueToBeAdded)
            break;
        case 'y': //add years
            DateToWorkOn.setYear(DateToWorkOn.getFullYear() + ValueToBeAdded)
            break;
        case 'h': //add hours
            DateToWorkOn.setHours(DateToWorkOn.getHours() + ValueToBeAdded)
            break;
        case 'n': //add minutes
            DateToWorkOn.setMinutes(DateToWorkOn.getMinutes() + ValueToBeAdded)
            break;
        case 's': //add seconds
            DateToWorkOn.setSeconds(DateToWorkOn.getSeconds() + ValueToBeAdded)
            break;
    }
    return DateToWorkOn;
}

function formatDuration(minutes) {
    var duration;
    switch (minutes)
    {
        case checkRange(minutes, 0, 60):
            return minutes + " minutes";
            break;
        case checkRange(minutes, 0, 1440):
            duration = Math.floor(minutes / 60 % 24) + " hours"

            if (Math.round(((minutes / 60 % 24) % 1) * 60) != 0) {
                duration += " " + Math.round(((minutes / 60 % 24) % 1) * 60) + " minutes"
            }
            return duration
        default:
            duration = Math.floor(minutes / 1440 % 24) + " days"

            if (Math.floor(minutes / 60 % 24) != 0) {
                duration += " " + Math.floor(minutes / 60 % 24) + " hours"
            }

            if (Math.round(((minutes / 60 % 24) % 1) * 60) != 0) {
                duration += " " + Math.round(((minutes / 60 % 24) % 1) * 60) + " minutes"
            }
            return duration
            break;
    }
}

function checkRange(x, n, m) {
    if (x >= n && x <= m) { return x; }
    else { return !x; }
}

/* Date Formatting
-----------------------------------------------------------------------------*/
// TODO: use same function formatDate(date, [date2], format, [options])

function formatDate(date, format, options) {
    return formatDates(date, null, format, options);
}

function formatDates(date1, date2, format, options) {
    //options = options || defaults;
    var date = date1,
		otherDate = date2,
		i, len = format.length, c,
		i2, formatter,
		res = '';
    for (i = 0; i < len; i++) {
        c = format.charAt(i);
        if (c == "'") {
            for (i2 = i + 1; i2 < len; i2++) {
                if (format.charAt(i2) == "'") {
                    if (date) {
                        if (i2 == i + 1) {
                            res += "'";
                        } else {
                            res += format.substring(i + 1, i2);
                        }
                        i = i2;
                    }
                    break;
                }
            }
        }
        else if (c == '(') {
            for (i2 = i + 1; i2 < len; i2++) {
                if (format.charAt(i2) == ')') {
                    var subres = formatDate(date, format.substring(i + 1, i2), options);
                    if (parseInt(subres.replace(/\D/, ''), 10)) {
                        res += subres;
                    }
                    i = i2;
                    break;
                }
            }
        }
        else if (c == '[') {
            for (i2 = i + 1; i2 < len; i2++) {
                if (format.charAt(i2) == ']') {
                    var subformat = format.substring(i + 1, i2);
                    var subres = formatDate(date, subformat, options);
                    if (subres != formatDate(otherDate, subformat, options)) {
                        res += subres;
                    }
                    i = i2;
                    break;
                }
            }
        }
        else if (c == '{') {
            date = date2;
            otherDate = date1;
        }
        else if (c == '}') {
            date = date1;
            otherDate = date2;
        }
        else {
            for (i2 = len; i2 > i; i2--) {
                if (formatter = dateFormatters[format.substring(i, i2)]) {
                    if (date) {
                        res += formatter(date, options);
                    }
                    i = i2 - 1;
                    break;
                }
            }
            if (i2 == i) {
                if (date) {
                    res += c;
                }
            }
        }
    }
    return res;
};

function zeroPad(n) {
    return (n < 10 ? '0' : '') + n;
}

var dayNamesShort = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
var monthNamesShort = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
var dateFormatters = {
    s: function (d) { return d.getSeconds() },
    ss: function (d) { return zeroPad(d.getSeconds()) },
    m: function (d) { return d.getMinutes() },
    mm: function (d) { return zeroPad(d.getMinutes()) },
    h: function (d) { return d.getHours() % 12 || 12 },
    hh: function (d) { return zeroPad(d.getHours() % 12 || 12) },
    H: function (d) { return d.getHours() },
    HH: function (d) { return zeroPad(d.getHours()) },
    d: function (d) { return d.getDate() },
    dd: function (d) { return zeroPad(d.getDate()) },
    ddd: function (d, o) { return dayNamesShort[d.getDay()] },
    e: function (d, o) { return o.dayNamesShortest[d.getDay()] }, // add by JPAYNE 
    dddd: function (d, o) { return o.dayNames[d.getDay()] },
    M: function (d) { return d.getMonth() + 1 },
    MM: function (d) { return zeroPad(d.getMonth() + 1) },
    MMM: function (d, o) { return monthNamesShort[d.getMonth()] },
    MMMM: function (d, o) { return o.monthNames[d.getMonth()] },
    yy: function (d) { return (d.getFullYear() + '').substring(2) },
    yyyy: function (d) { return d.getFullYear() },
    t: function (d) { return d.getHours() < 12 ? 'a' : 'p' },
    tt: function (d) { return d.getHours() < 12 ? 'am' : 'pm' },
    T: function (d) { return d.getHours() < 12 ? 'A' : 'P' },
    TT: function (d) { return d.getHours() < 12 ? 'AM' : 'PM' },
    u: function (d) { return formatDate(d, "yyyy-MM-dd'T'HH:mm:ss'Z'") },
    S: function (d) {
        var date = d.getDate();
        if (date > 10 && date < 20) {
            return 'th';
        }
        return ['st', 'nd', 'rd'][date % 10 - 1] || 'th';
    }
};


function parseDate(s, ignoreTimezone) { // ignoreTimezone defaults to true
    if (typeof s == 'object') { // already a Date object
        return s;
    }
    if (typeof s == 'number') { // a UNIX timestamp
        return new Date(s * 1000);
    }
    if (typeof s == 'string') {
        if (s.match(/^\d+$/)) { // a UNIX timestamp
            return new Date(parseInt(s, 10) * 1000);
        }
        if (ignoreTimezone === undefined) {
            ignoreTimezone = true;
        }
        return parseISO8601(s, ignoreTimezone) || (s ? new Date(s) : null);
    }
    // TODO: never return invalid dates (like from new Date(<string>)), return null instead
    return null;
}
//fc.applyAll = applyAll;

function parseISO8601(s, ignoreTimezone) { // ignoreTimezone defaults to false
    // derived from http://delete.me.uk/2005/03/iso8601.html
    // TODO: for a know glitch/feature, read tests/issue_206_parseDate_dst.html
    var m = s.match(/^([0-9]{4})(-([0-9]{2})(-([0-9]{2})([T ]([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?$/);
    if (!m) {
        return null;
    }
    var date = new Date(m[1], 0, 1);
    if (ignoreTimezone || !m[14]) {
        var check = new Date(m[1], 0, 1, 9, 0);
        if (m[3]) {
            date.setMonth(m[3] - 1);
            check.setMonth(m[3] - 1);
        }
        if (m[5]) {
            date.setDate(m[5]);
            check.setDate(m[5]);
        }
        fixDate(date, check);
        if (m[7]) {
            date.setHours(m[7]);
        }
        if (m[8]) {
            date.setMinutes(m[8]);
        }
        if (m[10]) {
            date.setSeconds(m[10]);
        }
        if (m[12]) {
            date.setMilliseconds(Number("0." + m[12]) * 1000);
        }
        fixDate(date, check);
    } else {
        date.setUTCFullYear(
			m[1],
			m[3] ? m[3] - 1 : 0,
			m[5] || 1
		);
        date.setUTCHours(
			m[7] || 0,
			m[8] || 0,
			m[10] || 0,
			m[12] ? Number("0." + m[12]) * 1000 : 0
		);
        var offset = Number(m[16]) * 60 + Number(m[17]);
        offset *= m[15] == '-' ? 1 : -1;
        date = new Date(+date + (offset * 60 * 1000));
    }
    return date;
}

function fixDate(d, check) { // force d to be on check's YMD, for daylight savings purposes
    if (+d) { // prevent infinite looping on invalid dates
        while (d.getDate() != check.getDate()) {
            d.setTime(+d + (d < check ? 1 : -1) * HOUR_MS);
        }
    }
}
