/* calendar */
var urlHashes = ['v=', 'f1=', 'f2=', 'f3=', 'f4=', 'f5=', 'f6=', 'f7=', 'f8=', 'f9=', 'f10='];
var vHashes = [];
var f1Hashes = [];
var f2Hashes = [];
var f3Hashes = [];
var f4Hashes = [];
var f5Hashes = [];
var f6Hashes = [];
var f7Hashes = [];
var f8Hashes = [];
var f9Hashes = [];
var f10Hashes = [];
var allHashes = "";
var today = moment();
var currentDate = today.format('D');
var currentMonth = today.format('MM');
var currentYear = today.format('YYYY');
var nextMonth = today.add(1, 'month').format('MM');
if (nextMonth == "01") {
    var nextMonthYear = today.add(1, 'year').format('YYYY');
} else {
    var nextMonthYear = today.format('YYYY');
}
var previousMonth = today.subtract(1, 'month').format('MM');
if (previousMonth == "12") {
    var previousMonthYear = today.subtract(1, 'year').format('YYYY');
} else {
    var previousMonthYear = today.format('YYYY');
}
var checkedEvents = [];
var allData = [];
var allDataURLs = [];
var currentDataURLs = [];
var currentData = [];
var sideFeatures = [];
var sideFeaturesURL = [];
var currentLoadedView = defaultView;
var lastLoadedMonth = "";
var lastLoadedYear = "";
var currentURL = window.location.href;
var hash = "";
var newHash = "";
var hashClass = "";
var hashArray = [];
var newHashArray = [];
var newSetHashArray = [];
var setFiltersLoad = "";
var $eventsContainer = $(".events .events-list");
var $featuredEventsContainer = $(".featured-events-list");
var eventList = "";
var eventItem = "";
var $loadMoreContainer = $(".events .load-more");
var $eventViewHeader = $("h1#events-view");
var $eventViewCountDisplay = $(".events-results .event-count");
var $eventFilterViewCountDisplay = $(".events-results .filter-count");
var $eventsMessageContainer = $(".events-results .events-message");
var eventsMessage = "";
var errorMessage = false;
var rangeDates = [];
var rangeDateStart = "";
var rangeDateEnd = "";
var startYearRange = "";
var endYearRange = "";
var startMonthRange = "";
var endMonthRange = "";
var startDayRange = "";
var endDayRange = "";
var singleDate = "";
var singleDateYear = "";
var singleDateMonth = "";
var singleDateDay = "";
var startDate = "";
var endDate = "";

$(document).ready(function() {
    $(window).scroll(function() {
        if ($(this).scrollTop() > 100) {
            $(".hh-module #back-to-top").fadeIn();
        } else {
            $(".hh-module  #back-to-top").fadeOut();
        }
    });
    $(".hh-module  #back-to-top").click(function() {
        $("body,html").animate({
            scrollTop: 0
        }, 800);
        return false;
    });
    if ($('.events-listing').length) {
        $('#mini-calendar .input-daterange').datepicker({
            todayHighlight: true,
        });
        $('#startDate').datepicker().on('changeDate', function(startDateData) {
            $eventsContainer.empty();
            startDate = moment(startDateData.date).format("MM/DD/YYYY");
            if (endDate == "" || endDate == startDate) {
                setHash("v=", "replace", startDate, function() {
                    eventCount();
                    loadView(startDate).then(function(results) {
                        showEvents(results.events, results.view, results.target, results.showLimit, results.origin);
                    });
                });
            } else {
                setHash("v=", "replace", startDate + "-" + endDate, function() {
                    eventCount();
                    loadView(startDate + "-" + endDate).then(function(results) {
                        showEvents(results.events, results.view, results.target, results.showLimit, results.origin);
                    });
                });
            }
        });
        $('#endDate').datepicker().on('changeDate', function(endDateData) {
            $eventsContainer.empty();
            if (startDate != "") {
                endDate = moment(endDateData.date).format("MM/DD/YYYY");
                if (startDate == endDate) {
                    setHash("v=", "replace", startDate, function() {
                        loadView(startDate).then(function(results) {
                            showEvents(results.events, results.view, results.target, results.showLimit, results.origin);
                        });
                    });
                } else {
                    setHash("v=", "replace", startDate + "-" + endDate, function() {
                        loadView(startDate + "-" + endDate).then(function(results) {
                            showEvents(results.events, results.view, results.target, results.showLimit, results.origin);
                        });
                    });
                }
            }
        });
        $(".date-views button").click(function() {
            $(".date-views button").each(function() {
                $(this).removeClass("active");
            });
            $(this).addClass("active");
        });
        $eventsContainer.tooltip({
            selector: "[data-toggle='tooltip']"
        });
        $(".hh-events .plus-toggle").click(function() {
            $(".hh-events .plus-toggle").toggleClass("fa-plus-circle fa-minus-circle");
            $(".hh-events .sidebar").toggleClass("expanded collapsed");
            if ($(".hh-events .sidebar").hasClass("expanded")) {
                $(".hh-events .plus-toggle").attr("title", "Collapse");
                $(".hh-events .plus-toggle ~ span").html("Collapse");
            } else {
                $(".hh-events .plus-toggle").attr("title", "Expand");
                $(".hh-events .plus-toggle ~ span").html("Expand");
            }
        });
        $(".checkboxes input").click(function() {
            $(this).blur();
        });
        $(".events").on('click', '.loadMoreEvents', function() {
            if (debugMode) {
                console.log("------------------------");
                console.log("loadMoreEvents");
            }
            showEvents(currentData, currentLoadedView, $eventsContainer, loadMoreCount, "loadMore");
            searchText($("#search").val().toLowerCase());
        });
        $(".events").on('click', '.loadAllEvents', function() {
            if (debugMode) {
                console.log("------------------------");
                console.log("loadAllEvents");
            }
            showEvents(currentData, currentLoadedView, $eventsContainer, "all", "loadAll");
            searchText($("#search").val().toLowerCase());
        });
        $(".clearAll").on("click", function() {
            if (debugMode) {
                console.log("------------------------");
                console.log("clearAll");
            }
            $(this).blur();
            $eventFilterViewCountDisplay.empty();
            $eventViewCountDisplay.empty();
            $('.input-daterange input').datepicker('update', null);
            $('.input-daterange').datepicker('updateDates');
            removeHash();
            $("#search").val('');
            setViewsLoad = "";
            setFiltersLoad = "";
            $("select.loadFilter").val("*");
            $(".loadFilter:checkbox:checked").each(function() {
                $(this).prop("checked", false);
            });
            $(".date-views button").each(function() {
                $(this).removeClass("active");
            });
            loadView(defaultView, "", "", "clearAll").then(function(results) {
                showEvents(results.events, results.view, results.target, results.showLimit, results.origin);
            });
        });
        checkHash();
        $(window).on('popstate', function() {
            checkHash();
        });
    }
    if ($('.events-detail').length) {
        $('.events-detail').tooltip({
            selector: "[data-toggle='tooltip']"
        });
        if ($('.events-detail .sTime').length) {
            var sZone = moment.tz.guess();
            var sTimezone = moment.tz(sZone).zoneAbbr();
            $(".events-detail .sTime").append(timeOutput(thisCurrentEvent[0].startDate, thisCurrentEvent[0].endDate, thisCurrentEvent[0].allDay, thisCurrentEvent[0].originalStart));
            if (thisCurrentEvent[0].allDay != "true") {
                $(".events-detail .sTime").append(" " + sTimezone);
            }
        }
        if ($('.events-detail .rDate').length) {
            currentRecurringEvent();
            $("#rDates").change(function(e) {
                $(".save-row .feeds").empty();
                $(".save-row .feeds").append(saveLinkOutput($(this).find(':selected').data('title'), $(this).find(':selected').data('desc'), $(this).find(':selected').data('start'), $(this).find(':selected').data('end'), $(this).find(':selected').data('timezone'), $(this).find(':selected').data('allDay'), "google"));
                $(".save-row .feeds").append(saveLinkOutput($(this).find(':selected').data('title'), $(this).find(':selected').data('desc'), $(this).find(':selected').data('start'), $(this).find(':selected').data('end'), $(this).find(':selected').data('timezone'), $(this).find(':selected').data('allDay'), "outlook"));
                $(".save-row .feeds").append(saveLinkOutput($(this).find(':selected').data('title'), $(this).find(':selected').data('desc'), $(this).find(':selected').data('start'), $(this).find(':selected').data('end'), $(this).find(':selected').data('timezone'), $(this).find(':selected').data('allDay'), "yahoo"));
                $(".save-row .feeds").append(saveLinkOutput($(this).find(':selected').data('title'), $(this).find(':selected').data('desc'), $(this).find(':selected').data('start'), $(this).find(':selected').data('end'), $(this).find(':selected').data('timezone'), $(this).find(':selected').data('allDay'), "ics"));
            });
            setTimeout(function() {
                if ($('.events-detail .related-events').length) {
                    relatedEventsAjax();
                }
            }, 300);
        } else {
            if ($('.events-detail .related-events').length) {
                relatedEventsAjax();
            }
        }
    }
    if ($('.hh-events-block').length) {
        blockEvents();
    }
});

/* data */

function checkDataURLs(data, view, target, showLimit, origin) {
    return new Promise(function(resolve, reject) {
        if (debugMode) {
            console.log("checkDataURLs");
        }
        awaitAll(data, getDataFromURLs).then(function(results) {
            var URLData = [];
            for (let i = 0; i < results.length; i++) {
                URLData = URLData.concat(results[i]);
            }
            URLData = _.uniqBy(URLData, 'id');
            calculateRecurrences(URLData).then(function(resultsR) {
                eventDateChecker(URLData, resultsR, view).then(function(results) {
                    // console.log(1);
                    // console.log(results);
                    jsonToCurrentData(results).then(function(results) {
                        // console.log(2);
                        // console.log(results);
                        results.jsonToCurrentDataEvents.sort(function(a, b) {
                            return +new Date(a.startDate) - +new Date(b.startDate);
                        });
                        resolve({
                            "events": results.jsonToCurrentDataEvents,
                            "view": view,
                            "target": target,
                            "showLimit": showLimit,
                            "origin": origin
                        });
                    });
                });
            });
        });
    })
}

function getFeaturedDataFromURLs(currentDataURL) {
    return new Promise(function(resolve, reject) {
        if (debugMode) {
            console.log("getFeaturedDataFromURLs: " + currentDataURL);
        }
        $.ajax({
            url: currentDataURL,
            success: function(data) {
                resolve(data.events);
            },
            error: function(data) {
                if (data.status == 200) {
                    resolve({
                        Error: "JSON Not Valid: " + currentDataURL
                    });
                    console.log("JSON Not Valid: " + currentDataURL);
                } else {
                    resolve({
                        Error: "Data URL Not Found: " + currentDataURL
                    });
                    console.log("Data URL Not Found: " + currentDataURL);
                }
            }
        });
    })
}

function getDataFromURLs(currentDataURL) {
    return new Promise(function(resolve, reject) {
        if (_.includes(allDataURLs, currentDataURL)) {
            if (debugMode) {
                console.log("getDataFromURLs bypassed: " + currentDataURL);
                console.log({
                    "allDataIn": allData
                });
            }
            resolve(allData);
        } else {
            if (debugMode) {
                console.log("getDataFromURLs: " + currentDataURL);
            }
            $.ajax({
                url: currentDataURL,
                success: function(data) {
                    if (debugMode) {
                        console.log({
                            "allDataOut": allData
                        });
                        console.log({
                            "newDataIn": data.events
                        });
                    }
                    if(data.events != undefined){
                        allData = allData.concat(data.events);
                    }
                    
                    // allData = _.filter(allData, _.isEmpty);
                    if (debugMode) {
                        console.log({
                            "allData": allData
                        });
                    }
                    resolve(allData);
                
                    // resolve(data.events);
                    allDataURLs.push(currentDataURL);
                },
                error: function(data) {
                    if (data.status == 200) {
                        resolve({
                            Error: "JSON Not Valid: " + currentDataURL
                        });
                        console.log("JSON Not Valid: " + currentDataURL);
                    } else {
                        resolve({
                            Error: "Data URL Not Found: " + currentDataURL
                        });
                        console.log("Data URL Not Found: " + currentDataURL);
                    }
                }
            });
        }
    })
}

function eventDateChecker(data, dataR, view) {
    return new Promise(function(resolve, reject) {
        checkedEvents = [];
        if (debugMode) {
            console.log("eventDateChecker: " + view);
        }
        if (view === "featured" || view === "side-featured-events") {
            if (data != undefined && data.length != 0) {
                for (let i = 0; i < data.length; i++) {
                    if (data[i] != undefined && data[i].featured == "true" && data[i].recurringEvent != "true") {
                        eventDateCheck(data[i], view);
                    }
                }
            }
            if (dataR != undefined && dataR.length != 0) {
                for (let i = 0; i < dataR.length; i++) {
                    if (data[i] != undefined && dataR[i].featured == "true") {
                        eventDateCheck(dataR[i], view);
                    }
                }
            }
        } else {
            if (data != undefined && data.length != 0) {
                for (let i = 0; i < data.length; i++) {
                    if (data[i] != undefined){
                        if(data[i].recurringEvent != undefined && data[i].recurringEvent != "true") {
                            eventDateCheck(data[i], view);
                        }
                    }
                }
            }
            if (dataR != undefined && dataR.length != 0) {
                for (let i = 0; i < dataR.length; i++) {
                    eventDateCheck(dataR[i], view);
                }
            }
        }
        resolve(checkedEvents);
    });
}

function eventDateCheck(v, view) {
    if (v.startDate != undefined) {
        var startDateM = moment(v.startDate);
        if (view === "upcoming-events" || view === "featured" || view === "side-featured-events" || view === "related-events" || view === "current-recurring-event" || view === "hh-events-block") {
            if (startDateM.isSameOrAfter(moment())) {
                checkedEvents.push(v);
            }
        } else if (view === "today") {
            if (moment().isSame(startDateM, 'date')) {
                checkedEvents.push(v);
            }
        } else if (view === "tomorrow") {
            if (moment(moment().add(1, 'days')).isSame(startDateM, 'date')) {
                checkedEvents.push(v);
            }
        } else if (view === "this-week") {
            if (moment(startDateM).isSameOrAfter(moment().weekday(0), "day") && moment(startDateM).isSameOrBefore(moment().weekday(6), "day")) {
                checkedEvents.push(v);
            }
        } else if (view === "this-weekend") {
            if (moment(startDateM).isSameOrAfter(moment().weekday(5), "day") && moment(startDateM).isSameOrBefore(moment().weekday(7), "day")) {
                checkedEvents.push(v);
            }
        } else if (view === "next-week") {
            if (moment(startDateM).isSameOrAfter(moment().weekday(7), "day") && moment(startDateM).isSameOrBefore(moment().weekday(13), "day")) {
                checkedEvents.push(v);
            }
        } else if (view === "this-month") {
            if (moment().isSame(startDateM, 'month')) {
                checkedEvents.push(v);
            }
        } else if (view === "next-month") {
            if (moment().add(1, 'months').isSame(startDateM, 'month')) {
                checkedEvents.push(v);
            }
        } else {
            if (view === undefined || view == "") {
                checkedEvents.push(v);
            } else {;
                if (view.indexOf("-") > -1) {
                    if (startDateM.isSameOrAfter(moment(rangeDateStart, "MM/DD/YYYY")) && startDateM.isSameOrBefore(moment(rangeDateEnd, "MM/DD/YYYY"))) {
                        checkedEvents.push(v);
                    }
                } else {
                    if (startDateM.isSame(moment(view, "MM/DD/YYYY"), "day")) {
                        checkedEvents.push(v);
                    }
                }
            }
        }
    }
}

function jsonToCurrentData(data, view) {
    return new Promise(function(resolve, reject) {
        var jsonToCurrentDataEvents = [];
        for (let i = 0; i < data.length; i++) {
            cdEvent = {};
            cdEvent.id = data[i].id;
            cdEvent.title = data[i].title;
            cdEvent.startDate = data[i].startDate;
            cdEvent.endDate = data[i].endDate;
            cdEvent.originalStart = data[i].originalStart;
            cdEvent.allDay = data[i].allDay;
            cdEvent.description = data[i].description;
            cdEvent.recurringEvent = data[i].recurringEvent;
            cdEvent.tooltip = data[i].tooltip;
            cdEvent.image = data[i].image;
            cdEvent.alt = data[i].alt;
            cdEvent.featured = data[i].featured;
            if (filter1) {
                cdEvent.filter1 = data[i].filter1;
            }
            if (filter2) {
                cdEvent.filter2 = data[i].filter2;
            }
            if (filter3) {
                cdEvent.filter3 = data[i].filter3;
            }
            if (filter4) {
                cdEvent.filter4 = data[i].filter4;
            }
            if (filter5) {
                cdEvent.filter5 = data[i].filter5;
            }
            if (filter6) {
                cdEvent.filter6 = data[i].filter6;
            }
            if (filter7) {
                cdEvent.filter7 = data[i].filter7;
            }
            if (filter8) {
                cdEvent.filter8 = data[i].filter8;
            }
            if (filter9) {
                cdEvent.filter9 = data[i].filter9;
            }
            if (filter10) {
                cdEvent.filter10 = data[i].filter10;
            }
            cdEvent.url = data[i].url;
            jsonToCurrentDataEvents.push(cdEvent);

        }
        resolve({
            jsonToCurrentDataEvents: jsonToCurrentDataEvents
        });
    });
}

function eventCount() {
    $eventsMessageContainer.empty();
    $eventViewCountDisplay.empty();
    $eventFilterViewCountDisplay.empty();
    var $eventsList = $(".events-list");
    var $filterMatch = $eventsList.find(".filter-match");
    var $allEvents = $eventsList.find(".event");
    if ($allEvents.length != $filterMatch.length) {
        $eventViewCountDisplay.html("Loaded <span>" + $allEvents.length + "</span> event(s)");
        $eventFilterViewCountDisplay.html(", showing <span>" + $filterMatch.length + "</span> that meet your filter/search criteria. ");
    } else {
        $eventViewCountDisplay.html("Showing <span>" + $allEvents.length + "</span> event(s). ")
    }
    if ($allEvents.length <= 4 || $filterMatch.length <= 4) {
        $(".events-results2").removeClass("show-hhe").addClass("hide-hhe");
    } else {
        $(".events-results2").removeClass("hide-hhe").addClass("show-hhe");
    }
}

/* details */

function eventHTML(v, i, col) {
    if (col == undefined) {
        col = 4;
    }
    eventItem = '';
	let divisible = 12/col;
// 	if(i % divisible === 0 && i !== 0) {
// 		eventItem += '<div class="clearfix"></div>';
// 	}
    eventItem += '<div class="col-sm-6 col-md-' + col + ' event">';
    eventItem += '<a href="' + v.url + '" target="_parent">';
    eventItem += imageOutput(v.image, v.startDate);
    eventItem += '<h3 class="title">';
    eventItem += v.title;
    eventItem += '</h3>';
    eventItem += '</a>';
    eventItem += '<div class="details">';
    if (v.featured == "true") {
        eventItem += '<div class="featured">';
        eventItem += '<span class="far fa-star" aria-hidden="true"></span>';
        eventItem += '</div>';
    }
    if (v.recurringEvent == "true") {
        eventItem += '<div class="recurrence">';
        eventItem += '<span class="fas fa-sync-alt" title="' + v.tooltip + '" data-toggle="tooltip" data-placement="bottom" tabindex="0">';
        eventItem += '</span>';
        eventItem += '</div>';
    }
    eventItem += '<div class="time">' + timeOutput(v.startDate, v.endDate, v.allDay, v.originalStart) + '</div>';
    eventItem += '<div class="date">' + dateOutput(v.startDate, v.endDate) + '</div>';
    eventItem += '</div>';
    eventItem += '</div>';
    return eventItem;
}

function getRelatedEvents(data) {
    return new Promise(function(resolve) {
        for (let i = 0; i < data.length; i++) {
            eventList += eventHTML(data[i], i);
        };
        resolve({
            data: data,
            events: eventList
        });
    })
}

/* event */

function showEvents(data, view, target, showLimit, origin) {
    getEvents(data, showLimit, origin).then(function(results) {
        if (debugMode) {
            console.log("showEvents");
        }
        // target.empty();
        // target.append(results.events);
        target.html(results.events);
        searchText($("#search").val().toLowerCase());
        eventCount();
        if (setFiltersLoad.length > 0) {
            showFilter(setFiltersLoad, "showEvents")
        }
        if (view != "side-featured-events") {
            currentData = [];
            $loadMoreContainer.removeClass("show-hhe").addClass("hide-hhe");
            if (showLimit != "all") {
                currentData = _.drop(results.data, showLimit);
                if (currentData.length > 0) {
                    if (debugMode) {
                        console.log("show loadMore");
                    }
                    $loadMoreContainer.removeClass("hide-hhe").addClass("show-hhe");
                }
            }
        }
    })
}

function getEvents(data, showLimit, origin) {
    return new Promise(function(resolve, reject) {
        if (debugMode) {
            console.log("getEvents");
        }
        for (let iE = 0; iE < data.length; iE++) {
            var eventsListFilterDots = [];
            var eventsListFilterTexts = [];
            var filterClasses = [];
            var filterData = [
                { name: "f1", data: data[iE].filter1, eList: filter1EventsList}, { name: "f2", data: data[iE].filter2, eList: filter2EventsList }, { name: "f3", data: data[iE].filter3, eList: filter3EventsList }, { name: "f4", data: data[iE].filter4, eList: filter4EventsList }, { name: "f5", data: data[iE].filter5, eList: filter5EventsList }, { name: "f6", data: data[iE].filter6, eList: filter6EventsList }, { name: "f7", data: data[iE].filter7, eList: filter7EventsList }, { name: "f8", data: data[iE].filter8, eList: filter8EventsList }, { name: "f9", data: data[iE].filter9, eList: filter9EventsList }, { name: "f10", data: data[iE].filter10, eList: filter10EventsList }
            ];
            for (let iFD = 0; iFD < filterData.length; iFD++) {
                if (filterData[iFD].data) {
                    for (let iFDF = 0; iFDF < filterData[iFD].data.length; iFDF++) {
                        filterClasses.push(filterData[iFD].data[iFDF].replace(/\s/g, "-").replace(/&/g, "and").replace(/[^0-9a-z\-]/gi, "-").toLowerCase());
                    }
                    
                    for (let iFDF = 0; iFDF < filterData[iFD].data.length; iFDF++) {
                        if(filterData[iFD].eList == "dots"){
                            eventsListFilterDots.push({
                            "name": filterData[iFD].data[iFDF],
                            "filter": filterData[iFD].name
                            });
                        }
                        
                    }
                    for (let iFDF = 0; iFDF < filterData[iFD].data.length; iFDF++) {
                        if(filterData[iFD].eList == "text"){
                            eventsListFilterTexts.push(filterData[iFD].data[iFDF]);
                        }
                    }
                }
            }
            eventItem = '';
            eventItem += '<div class="row event filter-match ' + filterClasses.join(' ') + '">';
            eventItem += '<a href="' + data[iE].url + '" target="_parent">';
            eventItem += '<div class="col-xs-12 col-sm-4 image">';
            eventItem += imageOutput(data[iE].image, data[iE].startDate);
            eventItem += '</div>';
            eventItem += '<div class="col-xs-12 col-sm-8"><div class="event-details"><div>';
            eventItem += '<h3 class="title">';
            eventItem += data[iE].title;
            eventItem += '</h3>';
            eventItem += '<div class="details">';
            if (data[iE].featured === "true") {
                eventItem += '<div class="featured">';
                eventItem += '<span class="far fa-star" aria-hidden="true"></span>';
                eventItem += '</div>';
            }
            if (data[iE].recurringEvent === "true") {
                eventItem += '<div class="recurrence">';
                eventItem += '<span class="fas fa-sync-alt" title="' + data[iE].tooltip + '" data-toggle="tooltip" data-placement="bottom" tabindex="0">';
                eventItem += '</span>';
                eventItem += '</div>';
            }
            eventItem += '<div class="time">' + timeOutput(data[iE].startDate, data[iE].endDate, data[iE].allDay, data[iE].originalStart) + '</div>';
            eventItem += '<div class="date">' + dateOutput(data[iE].startDate, data[iE].endDate) + '</div>';
            if (eventsListFilterTexts.length > 0) {
                if (eventsListFilterTexts.length > 1) {
                    eventItem += '<div class="location listFilterText">' + eventsListFilterTexts.join(', ') + '</div>';
                } else {
                    eventItem += '<div class="location listFilterText">' + eventsListFilterTexts.join('') + '</div>';
                }
            }
            if (eventsListFilterDots.length > 0) {
                // console.log(eventsListFilterDots);
                eventItem += '<div class="categories listFilterDots">';
                for (let i = 0; i < eventsListFilterDots.length; i++) {
                    eventItem += '<span class="fas fa-circle dot ' + eventsListFilterDots[i].filter + "-" + eventsListFilterDots[i].name.replace(/\s/g, "-").replace(/,/g, "").replace(/&/g, "and").replace(/[^0-9a-z\-]/gi, "").toLowerCase() + '-color" title="' + eventsListFilterDots[i].name + '" data-toggle="tooltip" data-placement="bottom" tabindex="0"></span>';
                };
                eventItem += '</div>';
            }
            eventItem += '</div>';
            if (data[iE].description != undefined) {
                eventItem += '<p class="summary">' + data[iE].description + '</p>';
            }
            eventItem += '</div></div></div>';
            eventItem += '</a>';
            eventItem += '</div>';
            eventList += eventItem;
            if (showLimit != "all" && iE == (showLimit - 1)) {
                break;
            }
        }
        resolve({
            data: data,
            events: eventList
        });
    })
}

/* filters */

$(".loadFilter:checkbox").change(function(e) {
    if (e.originalEvent !== undefined) {
        if (debugMode) {
            console.log("------------------------");
            console.log("applyFilter: " + $(this).val());
        }
        var thisChecked = $(this).val().replace(/\s/g, "-").replace(/,/g, "").replace(/&/g, "and").replace(/[^0-9a-z\-]/gi, "").toLowerCase();
        var hashChecked = $(this).data('hash') + "=";;
        loadView(currentLoadedView, "", "all", "filter").then(function(results) {
            showEvents(results.events, results.view, results.target, results.showLimit, results.origin);
            if (window.location.hash) {
                if (!_.includes(window.location.hash, hashChecked)) {
                    if (debugMode) {
                        console.log("filter add: " + hashChecked + thisChecked);
                    }
                    getHash(window.location.hash, hashChecked, function() {
                        setHash(hashChecked, "add", thisChecked, function() {
                            showFilter(setFiltersLoad, "loadView 1")
                        });
                    });
                } else if (_.includes(window.location.hash, hashChecked)) {
                    if (_.includes(window.location.hash, thisChecked)) {
                        if (debugMode) {
                            console.log("filter remove: " + thisChecked + " from " + hashChecked);
                        }
                        getHash(window.location.hash, hashChecked, function() {
                            setHash(hashChecked, "remove", thisChecked, function() {
                                showFilter(setFiltersLoad, "loadView 3")
                            });
                        });
                    } else {
                        if (debugMode) {
                            console.log("filter add: " + thisChecked + " to " + hashChecked);
                        }
                        getHash(window.location.hash, hashChecked, function() {
                            setHash(hashChecked, "add", thisChecked, function() {
                                showFilter(setFiltersLoad, "loadView 2")
                            });
                        });
                    }
                }
            } else {
                if (debugMode) {
                    console.log("filter add: " + hashChecked + thisChecked);
                }
                getHash(window.location.hash, hashChecked, function() {
                    setHash(hashChecked, "add", thisChecked, function() {
                        showFilter(setFiltersLoad, "loadView 1")
                    });
                });
            }
        });
    }
});

$("select.loadFilter").change(function(e) {
    if (e.originalEvent !== undefined) {
        if (debugMode) {
            console.log("------------------------");
            console.log("applyFilter: " + $(this).val());
        }
        var thisSelected = $(this).val().replace(/\s/g, "-").replace(/,/g, "").replace(/&/g, "and").replace(/[^0-9a-z\-]/gi, "").toLowerCase();
        var selectedHash = $(this).data('hash') + "=";
        loadView(currentLoadedView, "", "all", "filter").then(function(results) {
            showEvents(results.events, results.view, results.target, results.showLimit, results.origin);
            if (_.includes(window.location.hash, selectedHash)) {
                if (debugMode) {
                    console.log("filter replace " + selectedHash + thisSelected);
                }
                getHash(window.location.hash, selectedHash, function() {
                    setHash(selectedHash, "replace", thisSelected, function() {
                        showFilter(setFiltersLoad, "select.loadFilter");
                    });
                });
            } else {
                if (debugMode) {
                    console.log("filter add " + selectedHash + thisSelected);
                }
                getHash(window.location.hash, selectedHash, function() {
                    setHash(selectedHash, "add", thisSelected, function() {
                        showFilter(setFiltersLoad, "select.loadFilter 2");
                    });
                });
            }
        });
    };
});

let searchInput = document.getElementById('search');
let searchTimeout = null;
if(searchInput) {
    searchInput.addEventListener('keyup', function(e) {
        clearTimeout(searchTimeout);
        searchTimeout = setTimeout(function() {
            loadView(currentLoadedView, "", "all", "searchText").then(function(results) {
                showEvents(results.events, results.view, results.target, results.showLimit, results.origin);
                searchText($("#search").val().toLowerCase());
            });
        }, 300);
    });
}

function searchText(textSearch) {
    var doesEventContainText = function(eventElement) {
        var innerSelectors = ['.title', '.details', '.summary'];
        var innerElementMatchesText = function(selector) {
            var element = eventElement.querySelector(selector) || {
                innerText: ""
            };
            return element.innerText.toLowerCase().match(textSearch);
        };
        for (var i = 0; i < innerSelectors.length; i++) {
            if (innerElementMatchesText(innerSelectors[i])) {
                return true;
            }
        }
        return false;
    };
    if (debugMode) {
        console.log("searchText");
    }
    if (textSearch.length) {
        var $filterMatches = $eventsContainer.find('.filter-match');
        for (var i = 0; i < $filterMatches.length; i++) {
            var element = $filterMatches[i];
            if (!doesEventContainText(element)) {
                element.classList.remove("filter-match");
            }
        }
        eventCount();
    }
}

function showFilter(filter, origin) {
    if (debugMode) {
        console.log("showFilter");
        console.log("filter: " + filter);
        console.log("origin: " + origin);
    }
    if (filter.length > 1) {
        $eventsContainer.find('.row.event').removeClass("filter-match");
        $eventsContainer.find(filter).addClass("filter-match");
        eventCount();
        checkFilter(filter);
    } else {
        $eventsContainer.find('.row.event').addClass("filter-match");
        eventCount();
    }
}

function checkFilter(filter) {
    if (debugMode) {
        console.log("checkfilter");
        console.log(filter);
    }
    checkFilters = filter.replace(/, /g, '');
    checkFilters = checkFilters.split(".");
    checkFilters = _.compact(checkFilters);
    if (debugMode) {
        console.log(checkFilters);
    }
    for (let i = 0; i < checkFilters.length; i++) {
        $(".loadFilter:checkbox[value=" + checkFilters[i] + "]").prop("checked", "true");
    };
    for (let i = 0; i < checkFilters.length; i++) {
        var selectLoadFilters = document.querySelectorAll('select.loadFilter');
        for (iSLF = 0; iSLF < selectLoadFilters.length; ++iSLF) {
            for (iSO = 0; iSO < selectLoadFilters[iSLF].options.length; ++iSO) {
                if (checkFilters[i] == selectLoadFilters[iSLF].options[iSO].value) {
                    selectLoadFilters[iSLF].value = checkFilters[i];
                }
            };
        };
    };
}

/* hash */

function newHashF(newHash) {
    if (newHash !== window.location.hash) {
        removeHash();
        history.pushState(null, document.title, window.location.pathname + newHash);
    }
}

function getHash(hash, type, callback) {
    vHashes = [];
    f1Hashes = [];
    f2Hashes = [];
    f3Hashes = [];
    f4Hashes = [];
    f5Hashes = [];
    f6Hashes = [];
    f7Hashes = [];
    f8Hashes = [];
    f9Hashes = [];
    f10Hashes = [];
    if (hash) {
        getHashArray = hash + "&";
        getHashArray = getHashArray.replace("#", "").split("&");
        getHashArray = _.compact(getHashArray);

        for (let i = 0; i < getHashArray.length; i++) {
            if (_.includes(getHashArray[i], "v=")) {
                vHashes.push(getHashArray[i]);
            } else if (_.includes(getHashArray[i], "f1=")) {
                f1Hashes.push(getHashArray[i]);
            } else if (_.includes(getHashArray[i], "f2=")) {
                f2Hashes.push(getHashArray[i]);
            } else if (_.includes(getHashArray[i], "f3=")) {
                f3Hashes.push(getHashArray[i]);
            } else if (_.includes(getHashArray[i], "f4=")) {
                f4Hashes.push(getHashArray[i]);
            } else if (_.includes(getHashArray[i], "f5=")) {
                f5Hashes.push(getHashArray[i]);
            } else if (_.includes(getHashArray[i], "f6=")) {
                f6Hashes.push(getHashArray[i]);
            } else if (_.includes(getHashArray[i], "f7=")) {
                f7Hashes.push(getHashArray[i]);
            } else if (_.includes(getHashArray[i], "f8=")) {
                f8Hashes.push(getHashArray[i]);
            } else if (_.includes(getHashArray[i], "f9=")) {
                f9Hashes.push(getHashArray[i]);
            } else if (_.includes(getHashArray[i], "f10=")) {
                f10Hashes.push(getHashArray[i]);
            }
        };
    }
    if (callback) {
        callback();
    }
}

function setHash(type, action, value, callback) {
    setViews = "";
    setViewsLoad = "";
    setFilters = "";
    setFiltersClean = "";
    setFiltersMerged = "";
    setFiltersLoad = "";
    if (type === "v=") {
        vHashes = [];
        vHashes.push(type + value);
    } else if (type === "f1=") {
        if (_.includes(f1Hashes.toString(), type)) {
            if (action === "add") {
                f1HashesString = f1Hashes.toString() + "," + value;
                f1Hashes = [];
                f1Hashes.push(f1HashesString);
            } else if (action === "remove") {
                f1HashesString = f1Hashes.toString().replace("," + value, "").replace(value + ",", "").replace(value, "");
                f1Hashes = [];
                if (f1HashesString != "f1=") {
                    f1Hashes.push(f1HashesString);
                }
            } else if (action === "replace") {
                f1Hashes = [];
                f1HashesString = type + value;
                if (f1HashesString != "f1=") {
                    f1Hashes.push(f1HashesString);
                }
            }
        } else {
            f1Hashes.push(type + value);
        }
    } else if (type === "f2=") {
        if (_.includes(f2Hashes.toString(), type)) {
            if (action === "add") {
                f2HashesString = f2Hashes.toString() + "," + value;
                f2Hashes = [];
                f2Hashes.push(f2HashesString);
            } else if (action === "remove") {
                f2HashesString = f2Hashes.toString().replace("," + value, "").replace(value + ",", "").replace(value, "");
                f2Hashes = [];
                if (f2HashesString != "f2=") {
                    f2Hashes.push(f2HashesString);
                }
            } else if (action === "replace") {
                f2Hashes = [];
                f2HashesString = type + value;
                if (f2HashesString != "f2=") {
                    f2Hashes.push(f2HashesString);
                }
            }
        } else {
            f2Hashes.push(type + value);
        }
    } else if (type === "f3=") {
        if (_.includes(f3Hashes.toString(), type)) {
            if (action === "add") {
                f3HashesString = f3Hashes.toString() + "," + value;
                f3Hashes = [];
                f3Hashes.push(f3HashesString);
            } else if (action === "remove") {
                f3HashesString = f3Hashes.toString().replace("," + value, "").replace(value + ",", "").replace(value, "");
                f3Hashes = [];
                if (f3HashesString != "f3=") {
                    f3Hashes.push(f3HashesString);
                }
            } else if (action === "replace") {
                f3Hashes = [];
                f3HashesString = type + value;
                if (f3HashesString != "f3=") {
                    f3Hashes.push(f3HashesString);
                }
            }
        } else {
            f3Hashes.push(type + value);
        }
    } else if (type === "f4=") {
        if (_.includes(f4Hashes.toString(), type)) {
            if (action === "add") {
                f4HashesString = f4Hashes.toString() + "," + value;
                f4Hashes = [];
                f4Hashes.push(f4HashesString);
            } else if (action === "remove") {
                f4HashesString = f4Hashes.toString().replace("," + value, "").replace(value + ",", "").replace(value, "");
                f4Hashes = [];
                if (f4HashesString != "f4=") {
                    f4Hashes.push(f4HashesString);
                }
            } else if (action === "replace") {
                f4Hashes = [];
                f4HashesString = type + value;
                if (f4HashesString != "f4=") {
                    f4Hashes.push(f4HashesString);
                }
            }
        } else {
            f4Hashes.push(type + value);
        }
    } else if (type === "f5=") {
        if (_.includes(f5Hashes.toString(), type)) {
            if (action === "add") {
                f5HashesString = f5Hashes.toString() + "," + value;
                f5Hashes = [];
                f5Hashes.push(f5HashesString);
            } else if (action === "remove") {
                f5HashesString = f5Hashes.toString().replace("," + value, "").replace(value + ",", "").replace(value, "");
                f5Hashes = [];
                if (f5HashesString != "f5=") {
                    f5Hashes.push(f5HashesString);
                }
            } else if (action === "replace") {
                f5Hashes = [];
                f5HashesString = type + value;
                if (f5HashesString != "f5=") {
                    f5Hashes.push(f5HashesString);
                }
            }
        } else {
            f5Hashes.push(type + value);
        }
    } else if (type === "f6=") {
        if (_.includes(f6Hashes.toString(), type)) {
            if (action === "add") {
                f6HashesString = f6Hashes.toString() + "," + value;
                f6Hashes = [];
                f6Hashes.push(f6HashesString);
            } else if (action === "remove") {
                f6HashesString = f6Hashes.toString().replace("," + value, "").replace(value + ",", "").replace(value, "");
                f6Hashes = [];
                if (f6HashesString != "f6=") {
                    f6Hashes.push(f6HashesString);
                }
            } else if (action === "replace") {
                f6Hashes = [];
                f6HashesString = type + value;
                if (f6HashesString != "f6=") {
                    f6Hashes.push(f6HashesString);
                }
            }
        } else {
            f6Hashes.push(type + value);
        }
    } else if (type === "f7=") {
        if (_.includes(f7Hashes.toString(), type)) {
            if (action === "add") {
                f7HashesString = f7Hashes.toString() + "," + value;
                f7Hashes = [];
                f7Hashes.push(f7HashesString);
            } else if (action === "remove") {
                f7HashesString = f7Hashes.toString().replace("," + value, "").replace(value + ",", "").replace(value, "");
                f7Hashes = [];
                if (f7HashesString != "f7=") {
                    f7Hashes.push(f7HashesString);
                }
            } else if (action === "replace") {
                f7Hashes = [];
                f7HashesString = type + value;
                if (f7HashesString != "f7=") {
                    f7Hashes.push(f7HashesString);
                }
            }
        } else {
            f7Hashes.push(type + value);
        }
    } else if (type === "f8=") {
        if (_.includes(f8Hashes.toString(), type)) {
            if (action === "add") {
                f8HashesString = f8Hashes.toString() + "," + value;
                f8Hashes = [];
                f8Hashes.push(f8HashesString);
            } else if (action === "remove") {
                f8HashesString = f8Hashes.toString().replace("," + value, "").replace(value + ",", "").replace(value, "");
                f8Hashes = [];
                if (f8HashesString != "f8=") {
                    f8Hashes.push(f8HashesString);
                }
            } else if (action === "replace") {
                f8Hashes = [];
                f8HashesString = type + value;
                if (f8HashesString != "f8=") {
                    f8Hashes.push(f8HashesString);
                }
            }
        } else {
            f8Hashes.push(type + value);
        }
    } else if (type === "f9=") {
        if (_.includes(f9Hashes.toString(), type)) {
            if (action === "add") {
                f9HashesString = f9Hashes.toString() + "," + value;
                f9Hashes = [];
                f9Hashes.push(f9HashesString);
            } else if (action === "remove") {
                f9HashesString = f9Hashes.toString().replace("," + value, "").replace(value + ",", "").replace(value, "");
                f9Hashes = [];
                if (f9HashesString != "f9=") {
                    f9Hashes.push(f9HashesString);
                }
            } else if (action === "replace") {
                f9Hashes = [];
                f9HashesString = type + value;
                if (f9HashesString != "f9=") {
                    f9Hashes.push(f9HashesString);
                }
            }
        } else {
            f9Hashes.push(type + value);
        }
    } else if (type === "f10=") {
        if (_.includes(f10Hashes.toString(), type)) {
            if (action === "add") {
                f10HashesString = f10Hashes.toString() + "," + value;
                f10Hashes = [];
                f10Hashes.push(f10HashesString);
            } else if (action === "remove") {
                f10HashesString = f10Hashes.toString().replace("," + value, "").replace(value + ",", "").replace(value, "");
                f10Hashes = [];
                if (f10HashesString != "f10=") {
                    f10Hashes.push(f10HashesString);
                }
            } else if (action === "replace") {
                f10Hashes = [];
                f10HashesString = type + value;
                if (f10HashesString != "f10=") {
                    f10Hashes.push(f10HashesString);
                }
            }
        } else {
            f10Hashes.push(type + value);
        }
    }
    setViews = vHashes.join();
    setViewsLoad = setViews.replace("v=", "");
    setFiltersMerged = "";
    setFilters = _.concat(f1Hashes, f2Hashes, f3Hashes, f4Hashes, f5Hashes, f6Hashes, f7Hashes, f8Hashes, f9Hashes, f10Hashes);
    setFiltersClean = _.compact(setFilters);
    setFiltersMerged = "&" + setFiltersClean.join("&");
    setFiltersLoad = setFiltersMerged;
    for (let i = 0; i < urlHashes.length; i++) {
        setFiltersLoad = setFiltersLoad.replace(urlHashes[i], "");
    };
    setFiltersLoad = setFiltersLoad.substring(1);
    setFiltersLoad = "." + setFiltersLoad;
    setFiltersLoad = setFiltersLoad.replace(/&/g, filterLogic).replace(/=/g, ".").replace(/,/g, filterLogic).replace(/\.\./g, ".").replace(/\. \./g, ".");
    if (debugMode) {
        console.log("------------------------");
        console.log({
            setViews
        });
        console.log({
            setViewsLoad
        });
        console.log({
            setFilters
        });
        console.log({
            setFiltersClean
        });
        console.log({
            setFiltersMerged
        });
        console.log({
            urlHashes
        });
        console.log({
            setFiltersLoad
        });
    }
    if (setFiltersLoad === ".") {
        setFiltersLoad = "";
    }
    if (setFiltersClean.length > 0) {
        if (setViews.length > 0) {
            setURLHash = "#" + setViews + setFiltersMerged;
        } else {
            setURLHash = "#" + setFiltersMerged.substring(1);
        }
    } else {
        setURLHash = "#" + setViews
    }
    if (setURLHash === "#") {
        newHashF("");
    } else {
        newHashF(setURLHash);
    }
    if (callback) {
        callback();
    }
}

function removeHash(callback) {
    history.pushState("", document.title, window.location.pathname + window.location.search);
    if (callback) {
        callback();
    }
}

/* recurring */

function calculateRecurrences(data) {
    if (debugMode) {
        console.log({
            "recurDataIn": data
        });
    }
    return new Promise(function(resolve, reject) {
        var recurringData = [];
        var daysArray = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
        var fullDayArray = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
        for (let i = 0; i < data.length; i++) {
            // console.log(data[i]);
            if (data[i] != undefined && data[i].recurringEvent === "true") { /* Get the date data */
                var startMoment = moment.parseZone(data[i].startDate);
                var _startMoment = startMoment.clone();
                var endMoment = moment.parseZone(data[i].endDate);
                var difference = endMoment.diff(startMoment);
                var untilMoment = moment.parseZone(data[i].recurringDetails.recurUntilDate); /* Get cancellations of recurring event */
                var cancellations = [];
                for (let iC = 0; iC < data[i].recurringDetails.recurCancellations.length; iC++) {
                    cancellations.push(data[i].recurringDetails.recurCancellations[iC])
                }; /* Calculate the recurring events */
                if (data[i].recurringDetails.recurFrequency === "daily") {
                    if (data[i].recurringDetails.recurInterval > 1) {
                        data[i].tooltip = "Every " + data[i].recurringDetails.recurInterval + " days";
                    } else {
                        data[i].tooltip = "Daily";
                    }
                    while (untilMoment.diff(startMoment, "s") >= 0) { /* Add the current event */
                        var thisRecurrence = $.extend({}, data[i]);
                        thisRecurrence.startDate = startMoment.valueOf();
                        thisRecurrence.endDate = endMoment.valueOf();
                        if (!checkCancellations(cancellations, thisRecurrence.startDate)) {
                            recurringData.push(thisRecurrence);
                        } /* Increment by X days */
                        startMoment.add(data[i].recurringDetails.recurInterval, "days").valueOf();
                        endMoment.add(data[i].recurringDetails.recurInterval, "days").valueOf();
                    }
                } else if (data[i].recurringDetails.recurFrequency === "weekly") {
                    if (data[i].recurringDetails.recurInterval > 1) {
                        data[i].tooltip = "Every " + data[i].recurringDetails.recurInterval + " weeks";
                    } else {
                        data[i].tooltip = "Weekly";
                    }
                    var untilMomentRecurs = untilMoment.clone().add(data[i].recurringDetails.recurInterval, "weeks"); /* Incase event stops recurring during the week it still has events */
                    if (data[i].recurringDetails.recurDays != undefined && data[i].recurringDetails.recurDays.length > 0) {
                        data[i].tooltip += " on ";
                        for (var day = 0; day < data[i].recurringDetails.recurDays.length; day++) {
                            data[i].tooltip += data[i].recurringDetails.recurDays[day];
                            if (day < data[i].recurringDetails.recurDays.length - 2) {
                                data[i].tooltip += ", ";
                            }
                            if (day == data[i].recurringDetails.recurDays.length - 2) {
                                data[i].tooltip += " & ";
                            }
                        }
                        while (untilMomentRecurs.diff(startMoment, "s") >= 0) { /* Loop over the selected days of the week */
                            for (var day = 0; day < data[i].recurringDetails.recurDays.length; day++) {
                                var thisDay = data[i].recurringDetails.recurDays[day];
                                startMoment.date(startMoment.date() + (daysArray.indexOf(thisDay) - startMoment.day()));
                                endMoment = startMoment.clone().add(difference, "ms"); /* Only add occurrences that are after the actual start date & before the actual until date */
                                if (startMoment.diff(_startMoment, "s") >= 0 && startMoment.diff(untilMoment, "s") <= 0) {
                                    var thisRecurrence = $.extend({}, data[i]);
                                    thisRecurrence.startDate = startMoment.valueOf();
                                    thisRecurrence.endDate = endMoment.valueOf();
                                    if (!checkCancellations(cancellations, thisRecurrence.startDate)) {
                                        recurringData.push(thisRecurrence);
                                    }
                                }
                            } /* Increment by X weeks */
                            startMoment.add(data[i].recurringDetails.recurInterval, "weeks");
                            endMoment.add(data[i].recurringDetails.recurInterval, "weeks");
                        }
                    } else {
                        while (untilMomentRecurs.diff(startMoment, "s") >= 0) { /* Add the current event */ /* Only add occurrences that are before the actual until date */
                            if (startMoment.diff(untilMoment, "s") <= 0) {
                                var thisRecurrence = $.extend({}, data[i]);
                                thisRecurrence.startDate = startMoment.valueOf();
                                thisRecurrence.endDate = endMoment.valueOf();
                                if (!checkCancellations(cancellations, thisRecurrence.startDate)) {
                                    recurringData.push(thisRecurrence);
                                }
                            } /* Increment by X weeks */
                            startMoment.add(data[i].recurringDetails.recurInterval, "weeks").valueOf();
                            endMoment.add(data[i].recurringDetails.recurInterval, "weeks").valueOf();
                        }
                    }
                } else if (data[i].recurringDetails.recurFrequency === "monthly") {
                    if (data[i].recurringDetails.recurInterval > 1) {
                        data[i].tooltip = "Every " + data[i].recurringDetails.recurInterval + " months";
                    } else {
                        data[i].tooltip = "Monthly";
                    }
                    if (data[i].recurringDetails.recurMonth === "day of the month") { /* The same day of the month on each month (1st, 2nd, etc) */
                        data[i].tooltip += " on the " + startMoment.format('Do') + " day";
                        while (untilMoment.diff(startMoment, "s") >= 0) { /* Ensure the date exists within the current month */
                            if (startMoment.date() == _startMoment.date()) {
                                var thisRecurrence = $.extend({}, data[i]);
                                thisRecurrence.startDate = startMoment.valueOf();
                                thisRecurrence.endDate = endMoment.valueOf();
                                if (!checkCancellations(cancellations, thisRecurrence.startDate)) {
                                    recurringData.push(thisRecurrence);
                                }
                            } /* Increment by X months */
                            startMoment.add(data[i].recurringDetails.recurInterval, "months");
                            if (startMoment.daysInMonth() >= _startMoment.date()) {
                                startMoment.date(_startMoment.date());
                            }
                            endMoment = startMoment.clone().add(difference, "ms");
                        }
                    } else if (data[i].recurringDetails.recurMonth === "day of the week") { /* The same day of the week of the month (2nd Tues of month) */
                        data[i].tooltip += " on the " + nth(Math.ceil(startMoment.date() / 7)) + " " + fullDayArray[startMoment.day()]; /* Add a monthly occurrence based on the original event's day of the week */ /* Determine the position of this day in the month (ie 1st, 2nd ...) */
                        var theWeek = Math.floor(startMoment.date() / 7),
                            theDay = startMoment.day() + 1,
                            tempMonth = startMoment.month();
                        while (untilMoment.diff(startMoment, "s") >= 0) { /* If we didn't roll over into the next month, add the event */
                            if (tempMonth === startMoment.month()) {
                                var thisRecurrence = $.extend({}, data[i]);
                                thisRecurrence.startDate = startMoment.valueOf();
                                thisRecurrence.endDate = endMoment.valueOf();
                                if (!checkCancellations(cancellations, thisRecurrence.startDate)) {
                                    recurringData.push(thisRecurrence);
                                }
                            } /* Figure out where the next month's first day lies and add the difference in days with the weekly position */
                            startMoment.add(data[i].recurringDetails.recurInterval, "months").date(1);
                            tempMonth = startMoment.month();
                            if (theDay <= startMoment.day()) {
                                startMoment.date((theDay - startMoment.day() + ((theWeek + 1) * 7)));
                            } else {
                                startMoment.date((theDay - startMoment.day() + (theWeek * 7)));
                            }
                            endMoment = startMoment.clone().add(difference, "ms");
                        }
                    }
                } else if (data[i].recurringDetails.recurFrequency === "yearly") {
                    if (data[i].recurringDetails.recurInterval > 1) {
                        data[i].tooltip = "Every " + data[i].recurringDetails.recurInterval + " years";
                    } else {
                        data[i].tooltip = "Yearly";
                    }
                    while (untilMoment.diff(startMoment, "s") >= 0) { /* Add the current event */
                        var thisRecurrence = $.extend({}, data[i]);
                        thisRecurrence.startDate = startMoment.valueOf();
                        thisRecurrence.endDate = endMoment.valueOf();
                        if (!checkCancellations(cancellations, thisRecurrence.startDate)) {
                            recurringData.push(thisRecurrence);
                        } /* Increment by X years */
                        startMoment.add(data[i].recurringDetails.recurInterval, "years").valueOf();
                        endMoment.add(data[i].recurringDetails.recurInterval, "years").valueOf();
                    }
                }
            }
        };
        if (debugMode) {
            console.log({
                "recurDataOut": recurringData
            });
        }
        resolve(recurringData);
    })
}

function checkCancellations(cancellations, checkDate) {
    var cancelled = false;
    if (cancellations.length > 0) {
        for (let i = 0; i < cancellations.length; i++) {
            cancelled = moment.parseZone(checkDate).isSame(cancellations[i], 'day');
            if (cancelled) {
                break;
            }
        };
    }
    return cancelled;
}

function nth(n) {
    return n + ["st", "nd", "rd"][((n + 90) % 100 - 10) % 10 - 1] || "th"
}

function recurringURLs(view) {
    if (debugMode) {
        console.log("recurringData");
    }
    return new Promise(function(resolve, reject) {
        viewChecker(view).then(function(results) {
            resolve(results);
        });
    })
}

/* view */

$(".loadView").on("click", function() {
    if (debugMode) {
        console.log("------------------------");
        console.log("clicked: " + $(this).text());
    }
    $(this).blur();
    $('.input-daterange input').datepicker('update', null);
    $('.input-daterange').datepicker('updateDates');
    clickedView = $(this).text().replace(/All /gi, "").replace(/ Events/gi, "").replace(/\s/g, "-").replace(/,/g, "").replace(/&/g, "and").replace(/[^0-9a-z\-]/gi, "").toLowerCase();
    getHash(window.location.hash, "", function() {
        setHash("v=", "replace", clickedView, function() {
            loadView(clickedView).then(function(results) {
                showEvents(results.events, results.view, results.target, results.showLimit, results.origin);
            });
        });
    });
});

function loadView(view, target, showLimit, origin) {
    return new Promise(function(resolve, reject) {
        if (debugMode) {
            console.log("loadView: " + view);
        }
        if (target === undefined || target == "") {
            target = $eventsContainer;
        }
        if (showLimit === undefined || showLimit == "") {
            showLimit = defaultViewCount;
        }
        if (view != "side-featured-events") {
            currentLoadedView = view;
        }
        eventList = "";
        // currentDataURLs = []; // weirdly fixes date range issue
        viewChecker(view).then(function(results) {
            if (view === "upcoming-events") {
                $eventViewHeader.html("Upcoming Events");
                checkDataURLs(results, view, target, showLimit, origin).then(function(results) {
                    resolve({
                        "events": results.events,
                        "view": results.view,
                        "target": results.target,
                        "showLimit": results.showLimit,
                        "origin": results.origin
                    });
                });
            } else if (view === "this-month") {
                $eventViewHeader.html("This Month's Events");
                checkDataURLs(results, view, target, "all").then(function(results) {
                    resolve({
                        "events": results.events,
                        "view": results.view,
                        "target": results.target,
                        "showLimit": results.showLimit,
                        "origin": results.origin
                    });
                });
            } else if (view === "today") {
                $eventViewHeader.html("Today's Events");
                checkDataURLs(results, view, target, "all").then(function(results) {
                    resolve({
                        "events": results.events,
                        "view": results.view,
                        "target": results.target,
                        "showLimit": results.showLimit,
                        "origin": results.origin
                    });
                });
            } else if (view === "tomorrow") {
                $eventViewHeader.html("Tomorrow's Events");
                checkDataURLs(results, view, target, "all").then(function(results) {
                    resolve({
                        "events": results.events,
                        "view": results.view,
                        "target": results.target,
                        "showLimit": results.showLimit,
                        "origin": results.origin
                    });
                });
            } else if (view === "this-week") {
                $eventViewHeader.html("This Week's Events");
                checkDataURLs(results, view, target, "all").then(function(results) {
                    resolve({
                        "events": results.events,
                        "view": results.view,
                        "target": results.target,
                        "showLimit": results.showLimit,
                        "origin": results.origin
                    });
                });
            } else if (view === "this-weekend") {
                $eventViewHeader.html("This Weekend's Events");
                checkDataURLs(results, view, target, "all").then(function(results) {
                    resolve({
                        "events": results.events,
                        "view": results.view,
                        "target": results.target,
                        "showLimit": results.showLimit,
                        "origin": results.origin
                    });
                });
            } else if (view === "next-week") {
                $eventViewHeader.html("Next Week's Events");
                checkDataURLs(results, view, target, "all").then(function(results) {
                    resolve({
                        "events": results.events,
                        "view": results.view,
                        "target": results.target,
                        "showLimit": results.showLimit,
                        "origin": results.origin
                    });
                });
            } else if (view === "this-month") {
                $eventViewHeader.html("This Month's Events");
                checkDataURLs(results, view, target, "all").then(function(results) {
                    resolve({
                        "events": results.events,
                        "view": results.view,
                        "target": results.target,
                        "showLimit": results.showLimit,
                        "origin": results.origin
                    });
                });
            } else if (view === "next-month") {
                $eventViewHeader.html("Next Month's Events");
                checkDataURLs(results, view, target, "all").then(function(results) {
                    resolve({
                        "events": results.events,
                        "view": results.view,
                        "target": results.target,
                        "showLimit": results.showLimit,
                        "origin": results.origin
                    });
                });
            } else if (view === "featured") {
                $eventViewHeader.html("Upcoming Featured Events");
                checkDataURLs(results, view, target, showLimit, origin).then(function(results) {
                    resolve({
                        "events": results.events,
                        "view": results.view,
                        "target": results.target,
                        "showLimit": results.showLimit,
                        "origin": results.origin
                    });
                });
            } else if (view === "side-featured-events") {
                checkDataURLs(results, view, target, "3", origin).then(function(results) {
                    resolve({
                        "events": results.events,
                        "view": results.view,
                        "target": results.target,
                        "showLimit": results.showLimit,
                        "origin": results.origin
                    });
                });
            } else {
                $eventViewHeader.html(view);
                checkDataURLs(results, view, target, "all").then(function(results) {
                    resolve({
                        "events": results.events,
                        "view": results.view,
                        "target": results.target,
                        "showLimit": results.showLimit,
                        "origin": results.origin
                    });
                });
            }
        });
    })
}

function viewChecker(view) {
    return new Promise(function(resolve, reject) {
        var currentDataUrlsViews = ["upcoming-events", "this-month", "today", "tomorrow", "this-week", "this-weekend", "next-week", "this-month", "next-month", "featured", "side-featured-events"];
        var pushToCurrentDataURLsIfRangeApplies = function(yearRange, monthRange) {
            if (currentYear === yearRange && monthRange >= previousMonth) {
                currentDataURLs.push(currentDataURL.replace(/&amp;/g, '&'));
            } else {
                for (let i = 0; i < dataFiles.length; i++) {
                    if (dataFiles[i].name === yearRange + "") {
                        currentDataURLs.push(dataFiles[i].link.replace(/&amp;/g, '&'));
                    }
                };
            }
        };
        if (currentDataUrlsViews.includes(view)) {
            currentDataURLs.push(currentDataURL.replace(/&amp;/g, '&'));
        } else {
            if (view.indexOf("-") > -1) {
                rangeDates = [];
                rangeDateStart = "";
                rangeDateEnd = "";
                startYearRange = "";
                endYearRange = "";
                startMonthRange = "";
                endMonthRange = "";
                startDayRange = "";
                endDayRange = "";
                rangeDates = view.split("-");
                rangeDateStart = rangeDates[0];
                rangeDateEnd = rangeDates[1];
                var rangeDateStartM = moment(rangeDateStart, "MM/DD/YYYY", true);
                var rangeDateEndM = moment(rangeDateEnd, "MM/DD/YYYY", true);
                if (!rangeDateStartM.isValid() && !moment(rangeDateEnd, "MM/DD/YYYY", true).isValid()) {
                    eventsMessage = rangeDateStart + "-" + rangeDateStart + " is not a valid date range.";
                    errorMessage = true;
                } else {
                    if (!rangeDateStartM.isValid()) {
                        eventsMessage = rangeDateStart + " is not a valid start date.";
                        errorMessage = true;
                    }
                    if (!rangeDateEndM) {
                        eventsMessage = rangeDateEnd + " is not a valid end date.";
                        errorMessage = true;
                    }
                }
                if (errorMessage) {
                    $eventsMessageContainer.html('<p>' + eventsMessage + '</p>').removeClass("hide-hhe").addClass("show-hhe");
                } else {
                    $eventsMessageContainer.removeClass("show-hhe").addClass("hide-hhe").empty();
                    startYearRange = rangeDateStartM.year();
                    endYearRange = rangeDateEndM.year();
                    startMonthRange = rangeDateStartM.month();
                    endMonthRange = rangeDateEndM.month();
                    startDayRange = rangeDateStartM.date();
                    endDayRange = rangeDateEndM.date();
                    if (startYearRange === endYearRange) {
                        if (startMonthRange === endMonthRange) {
                            pushToCurrentDataURLsIfRangeApplies(startYearRange, startMonthRange);
                        } else {
                            pushToCurrentDataURLsIfRangeApplies(startYearRange, startMonthRange);
                            pushToCurrentDataURLsIfRangeApplies(endYearRange, endMonthRange);
                        }
                    } else {
                        if (currentYear === startYearRange && startMonthRange >= previousMonth) {
                            currentDataURLs.push(currentDataURL.replace(/&amp;/g, '&'));
                        } else {
                            for (i = startYearRange; i <= endYearRange; ++i) {
                                for (let iDF = 0; iDF < dataFiles.length; iDF++) {
                                    if (dataFiles[iDF].name == i + "") {
                                        currentDataURLs.push(dataFiles[iDF].link.replace(/&amp;/g, '&'));
                                    }
                                };
                            }
                        }
                    }
                }
            } else {
                singleDateYear = "";
                singleDateMonth = "";
                singleDateDay = "";
                singleDate = "";
                var viewDateM = moment(view, "MM/DD/YYYY", true);
                if (!viewDateM.isValid()) {
                    errorMessage = true;
                    eventsMessage = '"' + view + '"' + " is not a valid view.";
                    $eventsMessageContainer.html(eventsMessage).removeClass("hide-hhe").addClass("show-hhe");
                } else {
                    $eventsMessageContainer.removeClass("show-hhe").addClass("hide-hhe").empty();
                }
                if (!errorMessage) {
                    singleDate = viewDateM.format('MM/DD/YYYY');
                    singleDateYear = viewDateM.year();
                    singleDateMonth = viewDateM.month();
                    singleDateDay = viewDateM.date();
                    pushToCurrentDataURLsIfRangeApplies(singleDateYear, singleDateMonth);
                }
            }
        }
        resolve(currentDataURLs);
    })
}

function awaitAll(list, asyncFn) {
    const promises = [];
    for (let i = 0; i < list.length; i++) {
        promises.push(asyncFn(list[i]));
    };
    return Promise.all(promises);
}

function urlText(s, preserveCR) {
    preserveCR = preserveCR ? '&#13;' : '\n';
    return ('' + s).replace(/%/g, '%25').replace(/&amp;/g, '%26').replace(/&/g, '%26').replace(/'/g, '%27').replace(/"/g, '%22').replace(/</g, '%20').replace(/>/g, '%3E').replace(/#/g, '%23').replace(/ /g, '%20').replace(/\r\n/g, preserveCR).replace(/[\r\n]/g, preserveCR);
}

function saveLinkOutput(title, description, startDate, endDate, timezone, allDay, calendar) {
    var startDateO = moment(startDate);
    var endDateO = moment(endDate);
    if (allDay == "true") {
        var ssd = startDateO.format('YYYYMMDD');
        var sed = endDateO.add(1, "days").format('YYYYMMDD');
        if (calendar == "outlook") {
            var ssd = startDateO.format('YYYY-MM-DD');
            var sed = endDateO.add(1, "days").format('YYYY-MM-DD');
        }
    } else {
        var ssd = startDateO.format('YYYYMMDDTHHmmZ');
        var sed = endDateO.format('YYYYMMDDTHHmmZ');
        if (calendar == "outlook") {
            var ssd = startDateO.format('YYYY-MM-DDTHH:mmZ');
            var sed = endDateO.add(1, "days").format('YYYY-MM-DDTHH:mmZ');
        }
    }
    var saveLinkOutput = "";
    if (calendar == "google") {
        saveLinkOutput += "<a href='https://calendar.google.com/calendar/r/eventedit?text=" + urlText(title) + "&amp;dates=" + ssd + "/" + sed + "&amp;details=" + urlText(description) + " ' target='_blank'>";
        saveLinkOutput += "<span class='fab fa-google' aria-hidden='true'></span> <span class='sr-only'>Add to</span>Google</a>";
    } else if (calendar == "outlook") {
        saveLinkOutput += "<a target='_blank' href='https://outlook.live.com/owa/?path=/calendar/action/compose&amp;startdt=" + ssd + "&amp;enddt=" + sed + "&amp;subject=" + urlText(title) + "&amp;body=" + urlText(description) + "&amp;allday=" + allDay + " ' target='_blank'>";
        saveLinkOutput += "<span class='fab fa-windows' aria-hidden='true'></span> <span class='sr-only'>Add to</span>Outlook</a>";
    } else if (calendar == "yahoo") {
        if (allDay == "true") {
            saveLinkOutput += "<a href='https://calendar.yahoo.com/?v=60&amp;view=d&amp;type=20&amp;title=" + urlText(title) + "&amp;st=" + ssd + "&amp;et=" + sed + "&amp;desc=" + urlText(description) + "&amp;dur=allday' target='_blank'>";
        } else {
            saveLinkOutput += "<a href='https://calendar.yahoo.com/?v=60&amp;view=d&amp;type=20&amp;title=" + urlText(title) + "&amp;st=" + ssd + "&amp;et=" + sed + "&amp;desc=" + urlText(description) + "' target='_blank'>";
        }
        saveLinkOutput += "<span class='fab fa-yahoo' aria-hidden='true'></span> <span class='sr-only'>Add to</span>Yahoo</a>";
    } else if (calendar == "ics") {
        saveLinkOutput += "<a href='" + thisCurrentEvent[0].ics + "' target='_blank'><span class='far fa-calendar-plus' aria-hidden='true'></span> <span class='sr-only'>Download as</span>iCal</a>";
    }
    return saveLinkOutput;
}

function currentRecurringEvent() {
    calculateRecurrences(thisCurrentEvent).then(function(resultsR) {
        eventDateChecker("", resultsR, "current-recurring-event").then(function(results) {
            jsonToCurrentData(results).then(function(results) {
                var rJCDE = results.jsonToCurrentDataEvents;
                if (rJCDE.length > 0) {
                    rJCDE.sort(function(a, b) {
                        return +new Date(a.startDate) - +new Date(b.startDate);
                    });

                    for (let i = 0; i < rJCDE.length; i++) {
                        $('.rDate').append("Next Occurrance:<br/>" + dateOutput(rJCDE[i].startDate, rJCDE[i].endDate, "full"));
                        $('#rDates').append('<option selected="selected" value="' + dateOutput(rJCDE[i].startDate, rJCDE[i].endDate, "full") + '" data-title="' + rJCDE[i].title + '" data-desc="' + rJCDE[i].description + '" data-start="' + rJCDE[i].startDate + '" data-end="' + rJCDE[i].endDate + '" data-timezone="' + thisCurrentEvent[0].timezone + '" data-allDay="' + rJCDE[i].allDay + '">' + dateOutput(rJCDE[i].startDate, rJCDE[i].endDate, "full") + '</option>');
                        $(".save-row .feeds").append(saveLinkOutput(rJCDE[i].title, rJCDE[i].description, rJCDE[i].startDate, rJCDE[i].endDate, thisCurrentEvent[0].timezone, rJCDE[i].allDay, "google"));
                        $(".save-row .feeds").append(saveLinkOutput(rJCDE[i].title, rJCDE[i].description, rJCDE[i].startDate, rJCDE[i].endDate, thisCurrentEvent[0].timezone, rJCDE[i].allDay, "outlook"));
                        $(".save-row .feeds").append(saveLinkOutput(rJCDE[i].title, rJCDE[i].description, rJCDE[i].startDate, rJCDE[i].endDate, thisCurrentEvent[0].timezone, rJCDE[i].allDay, "yahoo"));
                        $(".save-row .feeds").append(saveLinkOutput(rJCDE[i].title, rJCDE[i].description, rJCDE[i].startDate, rJCDE[i].endDate, thisCurrentEvent[0].timezone, rJCDE[i].allDay, "ics"));
                        if (i == 0) {
                            break;
                        }
                    };
                    for (let i = 0; i < rJCDE.length; i++) {
                        if (i > 0) {
                            $('#rDates').append('<option value="' + dateOutput(rJCDE[i].startDate, rJCDE[i].endDate, "full") + '" data-title="' + rJCDE[i].title + '" data-desc="' + rJCDE[i].description + '" data-start="' + rJCDE[i].startDate + '" data-end="' + rJCDE[i].endDate + '" data-timezone="' + thisCurrentEvent[0].timezone + '" data-allDay="' + rJCDE[i].allDay + '">' + dateOutput(rJCDE[i].startDate, rJCDE[i].endDate, "full") + '</option>');
                        }
                    };
                } else {
                    $('#rDates').remove();
                    $('.save-row').remove();
                    $('.rDate').append("This event has ended. It ran from<br/>" + moment(thisCurrentEvent[0].startDate).format('MMM D, YYYY') + " to " + moment(thisCurrentEvent[0].recurringDetails.recurUntilDate).format('MMM D, YYYY') + ".");
                }
            });
        });
    });
}

function checkHash() {
    if (window.location.hash) {
        loadView("side-featured-events", $featuredEventsContainer, sideFeaturedCount).then(function(results) {
            showEvents(results.events, results.view, results.target, results.showLimit, results.origin);
            if (debugMode) {
                console.log("------------------------");
                console.log("pageLoadHash");
            }
            getHash(window.location.hash, "", function() {
                setViews = vHashes.join();
                setViewsLoad = setViews.replace("v=", "");
                if (setViewsLoad.length < 1) {
                    setViewsLoad = defaultView;
                };
                setFiltersMerged = "";
                setFilters = _.concat(f1Hashes, f2Hashes, f3Hashes, f4Hashes, f5Hashes, f6Hashes, f7Hashes, f8Hashes, f9Hashes, f10Hashes);
                setFiltersClean = _.compact(setFilters);
                setFiltersMerged = "&" + setFiltersClean.join("&");
                setFiltersLoad = setFiltersMerged;
                for (let i = 0; i < urlHashes.length; i++) {
                    setFiltersLoad = setFiltersLoad.replace(urlHashes[i], "");
                };
                setFiltersLoad = setFiltersLoad.replace(/&/g, ".").replace(/=/g, ".").replace(/,/g, filterLogic).replace(/\.\./g, ".");
                if (setFiltersLoad === ".") {
                    setFiltersLoad = "";
                }
                loadView(setViewsLoad, "", "all", "pageLoad").then(function(results) {
                    showEvents(results.events, results.view, results.target, results.showLimit, results.origin);
                });
            });
        });
    } else {
        if (debugMode) {
            console.log("pageLoad: " + defaultView);
            console.log("------------------------");
        }
        loadView("side-featured-events", $featuredEventsContainer, sideFeaturedCount).then(function(results) {
            showEvents(results.events, results.view, results.target, results.showLimit, results.origin);
            if (debugMode) {
                console.log("------------------------");
            }
            loadView(defaultView, "", "", "pageLoad").then(function(results) {
                showEvents(results.events, results.view, results.target, results.showLimit, results.origin);
            });
        });
    }
}

function dateOutput(startDateIn, endDateIn, type) {
    var startDateM = moment(startDateIn);
    if (startDateM.isSame(endDateIn), 'day') {
        if (type == "full") {
            var dateOutput = startDateM.format('MMMM D, YYYY');
        } else {
            var dateOutput = startDateM.format('MMM D YYYY');
        }
    } else {
        var endDateM = moment(endDateIn);
        if (startDateM.isSame(endDateIn), 'year') {
            if (startDateM.isSame(endDateIn), 'month') {
                var dateOutput = startDateM.format('MMM D') + ' - ' + endDateM.format('D YYYY');
            } else {
                var dateOutput = startDateM.format('MMM D') + ' - ' + endDateM.format('MMM D YYYY');
            }
        } else {
            var dateOutput = startDateM.format('MMM D YYYY') + ' - ' + endDateM.format('MMM D YYYY');
        }
    }
    return dateOutput;
}

function imgWeekDay(day) {
    var daysOfWeek = ["Mon<span>day</span>", "Tue<span>sday</span>", "Wed<span>nesday</span>", "Thur<span>sday</span>", "Fri<span>day</span>", "Sat<span>urday</span>", "Sun<span>day</span>"];
    return daysOfWeek[day - 1];
}

function imageOutput(image, startDateIn) {
    var startDateM = moment(startDateIn);
    if (image) {
        var imageOuput = '<div class="event-image" style="background-image:url(' + image.url + ');"></div>';
    } else {
        var imageOuput = '<div class="event-image date-img"><div class="month">' + startDateM.format('MMM') + '</div><div class="day">' + startDateM.format('D') + '<div class="weekday">' + imgWeekDay(startDateM.isoWeekday()) + '</div></div></div>';
    }
    return imageOuput;
}

function timeOutput(startDateIn, endDateIn, allDayIn, originalStart) {
    var timeOutput = "";
    if (allDayIn === "true") {
        timeOutput = 'All Day';
    } else {
        var startDateInM = moment(startDateIn);
        var originalStartM = moment(originalStart);
        var endDateInM = moment(endDateIn);
        var stdOffset; /*Fix to remove daylight savings time*/
        if (startDateInM.isSame(originalStartM)) {
            stdOffset = originalStartM.utcOffset();
        } else {
            stdOffset = startDateInM.utcOffset();
        }
        var startDateInOffsetM = startDateInM.utcOffset(stdOffset);
        var endDateInOffsetM = endDateInM.utcOffset(stdOffset);
        var startFormat = ["h"];
        var endFormat = [];
        if (startDateInOffsetM.minute() > 0) {
            startFormat.push(":mm");
        }
        if (startDateInOffsetM.isSame(endDateInOffsetM)) {
            startFormat.push(" A");
        } else {
            if (startDateInOffsetM.format('A') != endDateInOffsetM.format('A')) {
                startFormat.push(" A");
            }
            endFormat.push("h");
            if (endDateInOffsetM.minute() > 0) {
                endFormat.push(":mm");
            }
            endFormat.push(" A");
        }
        timeOutput = startDateInOffsetM.format(startFormat.join(""));
        if (endFormat.length) {
            timeOutput += " - " + endDateInOffsetM.format(endFormat.join(""));
        }
    }
    return timeOutput;
}

function filterCheck(fcLogic, fcPush, fcEvent) {
    if (debugMode) {
        console.log("filterCheck");
    }
    var fMatch = 0;
    for (let i = 0; i < filterTexts.length; i++) {
        if (filterTexts[i]) {
            for (let iFT = 0; iFT < filterTexts[i].length; iFT++) {
                if (filterTexts[i][iFT]) {
                    var eventFilter = fcEvent['filter' + (i + 1)];
                    var eventFilterCheck = [];
                    if (Array.isArray(eventFilter)) {

                        for (let iEF = 0; iEF < eventFilter.length; iEF++) {
                            eventFilterCheck.push(eventFilter[iEF].toLowerCase().replace(/[^A-Za-z0-9]/g, ""));
                        };
                        if ($.inArray(filterTexts[i][iFT], eventFilterCheck) != -1) {
                            fMatch++
                        }
                    }
                }
            };
        }
    };
    if (fcLogic === "Or") {
        if (fMatch > 0) {
            fcPush.push(fcEvent);
        }
    } else if (fcLogic === "And") {
        if (fMatch == filterTextsAll.length) {
            fcPush.push(fcEvent);
        }
    }
}

function relatedEventsAjax() {
    $.ajax({
        url: currentDataURL.replace(/&amp;/g, '&'),
        success: function(URLData) {
            calculateRecurrences(URLData.events).then(function(resultsR) {
                eventDateChecker(URLData.events, resultsR, "related-events").then(function(results) {
                    jsonToCurrentData(results).then(function(results) {
                        var rJCDE = results.jsonToCurrentDataEvents;
                        rJCDE.sort(function(a, b) {
                            return +new Date(a.startDate) - +new Date(b.startDate);
                        });
                        for (let i = 0; i < rJCDE.length; i++) {
                            if (rJCDE[i].id != currentEventID) {
                                if (moment(rJCDE[i].startDate).diff() > 0) {
                                    filterCheck(relatedEventsFilterLogic, relatedEvents, rJCDE[i]);
                                }
                            }
                            if (relatedEvents.length >= 6) {
                                break;
                            }
                        };
                        if (relatedEvents.length > 0) {
                            getRelatedEvents(relatedEvents).then(function(results) {
                                $('.related-events .events').empty();
                                $('.related-events .events').append(results.events);
                                if (typeof afterHHRelatedEventsLoad == 'function') {
                                    setTimeout(function() {
                                        afterHHRelatedEventsLoad();
                                    }, 50);
                                }
                            });
                        } else {
                            $('.related-events .events').empty();
                            $('.related-events .events').append('<div><p style="text-align:center">No upcoming related events found.</p></div>');
                        }
                    });
                });
            });
        },
        error: function(data) {
            if (data.status == 200) {
                console.log("JSON Not Valid: " + currentDataURL);
            } else {
                console.log("Data URL Not Found: " + currentDataURL);
            }
        }
    });
}

function blockEvents() {
    $.ajax({
        url: currentDataURL.replace(/&amp;/g, '&'),
        success: function(URLData) {
            calculateRecurrences(URLData.events).then(function(resultsR) {
                eventDateChecker(URLData.events, resultsR, "hh-events-block").then(function(results) {
                    jsonToCurrentData(results).then(function(results) {
                        var rJCDE = results.jsonToCurrentDataEvents;
                        rJCDE.sort(function(a, b) {
                            return +new Date(a.startDate) - +new Date(b.startDate);
                        });
                        var blockEventsCount = 0;
                        if (hhEventsType == "current") {
                            for (let i = 0; i < rJCDE.length; i++) {
                                if (moment(rJCDE[i].startDate).diff() > 0) {
                                    blockEventsCount++;
                                    hhEvents.push(rJCDE[i]);
                                    if (blockEventsCount == hhEventsLimit) {
                                        break;
                                    }
                                }
                            };
                        } else {
                            for (let i = 0; i < rJCDE.length; i++) {
                                if (moment(rJCDE[i].startDate).diff() > 0) {
                                    filterCheck(hhEventsFilterLogic, hhEvents, rJCDE[i]);
                                }
                                if (hhEvents.length >= hhEventsLimit) {
                                    break;
                                }
                            };
                        }
                        if (hhEvents.length > 0) {
                            getBlockEvents(hhEvents).then(function(results) {
                                $('.hh-events-block .row.events').empty();
                                $('.hh-events-block .row.events').append(results.events);
                                if (typeof afterHHEventsLoad == 'function') {
                                    setTimeout(function() {
                                        afterHHEventsLoad();
                                    }, 50);
                                }
                            });
                        } else {
                            $('.hh-events-block .row.events').empty();
                            $('.hh-events-block .row.events').append('<div><p style="text-align:center">No upcoming events found.</p></div>');
                        }
                    });
                });
            });
        },
        error: function(data) {
            if (data.status == 200) {
                console.log("JSON Not Valid: " + currentDataURL);
            } else {
                console.log("Data URL Not Found: " + currentDataURL);
            }
        }
    });
}