/*!
FullCalendar v5.11.3
Docs & License: https://fullcalendar.io/
(c) 2022 Adam Shaw
*/
var FullCalendarICalendar = (function (exports, common, ICAL) {
    'use strict';

    function _interopNamespace(e) {
        if (e && e.__esModule) return e;
        var n = Object.create(null);
        if (e) {
            Object.keys(e).forEach(function (k) {
                if (k !== 'default') {
                    var d = Object.getOwnPropertyDescriptor(e, k);
                    Object.defineProperty(n, k, d.get ? d : {
                        enumerable: true,
                        get: function () {
                            return e[k];
                        }
                    });
                }
            });
        }
        n['default'] = e;
        return Object.freeze(n);
    }

    var ICAL__namespace = /*#__PURE__*/_interopNamespace(ICAL);

    /*! *****************************************************************************
    Copyright (c) Microsoft Corporation.

    Permission to use, copy, modify, and/or distribute this software for any
    purpose with or without fee is hereby granted.

    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
    REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
    AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
    INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
    LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
    OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
    PERFORMANCE OF THIS SOFTWARE.
    ***************************************************************************** */

    var __assign = function() {
        __assign = Object.assign || function __assign(t) {
            for (var s, i = 1, n = arguments.length; i < n; i++) {
                s = arguments[i];
                for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
            }
            return t;
        };
        return __assign.apply(this, arguments);
    };

    /* eslint-disable */
    var IcalExpander = /** @class */ (function () {
        function IcalExpander(opts) {
            this.maxIterations = opts.maxIterations != null ? opts.maxIterations : 1000;
            this.skipInvalidDates = opts.skipInvalidDates != null ? opts.skipInvalidDates : false;
            this.jCalData = ICAL__namespace.parse(opts.ics);
            this.component = new ICAL__namespace.Component(this.jCalData);
            this.events = this.component.getAllSubcomponents('vevent').map(function (vevent) { return new ICAL__namespace.Event(vevent); });
            if (this.skipInvalidDates) {
                this.events = this.events.filter(function (evt) {
                    try {
                        evt.startDate.toJSDate();
                        evt.endDate.toJSDate();
                        return true;
                    }
                    catch (err) {
                        // skipping events with invalid time
                        return false;
                    }
                });
            }
        }
        IcalExpander.prototype.between = function (after, before) {
            var _this = this;
            function isEventWithinRange(startTime, endTime) {
                return (!after || endTime >= after.getTime()) &&
                    (!before || startTime <= before.getTime());
            }
            function getTimes(eventOrOccurrence) {
                var startTime = eventOrOccurrence.startDate.toJSDate().getTime();
                var endTime = eventOrOccurrence.endDate.toJSDate().getTime();
                // If it is an all day event, the end date is set to 00:00 of the next day
                // So we need to make it be 23:59:59 to compare correctly with the given range
                if (eventOrOccurrence.endDate.isDate && (endTime > startTime)) {
                    endTime -= 1;
                }
                return { startTime: startTime, endTime: endTime };
            }
            var exceptions = [];
            this.events.forEach(function (event) {
                if (event.isRecurrenceException())
                    exceptions.push(event);
            });
            var ret = {
                events: [],
                occurrences: [],
            };
            this.events.filter(function (e) { return !e.isRecurrenceException(); }).forEach(function (event) {
                var exdates = [];
                event.component.getAllProperties('exdate').forEach(function (exdateProp) {
                    var exdate = exdateProp.getFirstValue();
                    exdates.push(exdate.toJSDate().getTime());
                });
                // Recurring event is handled differently
                if (event.isRecurring()) {
                    var iterator = event.iterator();
                    var next = void 0;
                    var i = 0;
                    var _loop_1 = function () {
                        i += 1;
                        next = iterator.next();
                        if (next) {
                            var occurrence_1 = event.getOccurrenceDetails(next);
                            var _b = getTimes(occurrence_1), startTime_1 = _b.startTime, endTime_1 = _b.endTime;
                            var isOccurrenceExcluded = exdates.indexOf(startTime_1) !== -1;
                            // TODO check that within same day?
                            var exception = exceptions.find(function (ex) { return ex.uid === event.uid && ex.recurrenceId.toJSDate().getTime() === occurrence_1.startDate.toJSDate().getTime(); });
                            // We have passed the max date, stop
                            if (before && startTime_1 > before.getTime())
                                return "break";
                            // Check that we are within our range
                            if (isEventWithinRange(startTime_1, endTime_1)) {
                                if (exception) {
                                    ret.events.push(exception);
                                }
                                else if (!isOccurrenceExcluded) {
                                    ret.occurrences.push(occurrence_1);
                                }
                            }
                        }
                    };
                    do {
                        var state_1 = _loop_1();
                        if (state_1 === "break")
                            break;
                    } while (next && (!_this.maxIterations || i < _this.maxIterations));
                    return;
                }
                // Non-recurring event:
                var _a = getTimes(event), startTime = _a.startTime, endTime = _a.endTime;
                if (isEventWithinRange(startTime, endTime))
                    ret.events.push(event);
            });
            return ret;
        };
        IcalExpander.prototype.before = function (before) {
            return this.between(undefined, before);
        };
        IcalExpander.prototype.after = function (after) {
            return this.between(after);
        };
        IcalExpander.prototype.all = function () {
            return this.between();
        };
        return IcalExpander;
    }());

    var eventSourceDef = {
        parseMeta: function (refined) {
            if (refined.url && refined.format === 'ics') {
                return {
                    url: refined.url,
                    format: 'ics',
                };
            }
            return null;
        },
        fetch: function (arg, onSuccess, onFailure) {
            var meta = arg.eventSource.meta;
            var internalState = meta.internalState;
            function handleICalEvents(errorMessage, iCalExpander, xhr) {
                if (errorMessage) {
                    onFailure({ message: errorMessage, xhr: xhr });
                }
                else {
                    onSuccess({ rawEvents: expandICalEvents(iCalExpander, arg.range), xhr: xhr });
                }
            }
            /*
            NOTE: isRefetch is a HACK. we would do the recurring-expanding in a separate plugin hook,
            but we couldn't leverage built-in allDay-guessing, among other things.
            */
            if (!internalState || arg.isRefetch) {
                internalState = meta.internalState = {
                    completed: false,
                    callbacks: [handleICalEvents],
                    errorMessage: '',
                    iCalExpander: null,
                    xhr: null,
                };
                requestICal(meta.url, function (rawFeed, xhr) {
                    var iCalExpander = new IcalExpander({
                        ics: rawFeed,
                        skipInvalidDates: true,
                    });
                    for (var _i = 0, _a = internalState.callbacks; _i < _a.length; _i++) {
                        var callback = _a[_i];
                        callback('', iCalExpander, xhr);
                    }
                    internalState.completed = true;
                    internalState.callbacks = [];
                    internalState.iCalExpander = iCalExpander;
                    internalState.xhr = xhr;
                }, function (errorMessage, xhr) {
                    for (var _i = 0, _a = internalState.callbacks; _i < _a.length; _i++) {
                        var callback = _a[_i];
                        callback(errorMessage, null, xhr);
                    }
                    internalState.completed = true;
                    internalState.callbacks = [];
                    internalState.errorMessage = errorMessage;
                    internalState.xhr = xhr;
                });
            }
            else if (!internalState.completed) {
                internalState.callbacks.push(handleICalEvents);
            }
            else {
                handleICalEvents(internalState.errorMessage, internalState.iCalExpander, internalState.xhr);
            }
        },
    };
    function requestICal(url, successCallback, failureCallback) {
        var xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);
        xhr.onload = function () {
            if (xhr.status >= 200 && xhr.status < 400) {
                successCallback(xhr.responseText, xhr);
            }
            else {
                failureCallback('Request failed', xhr);
            }
        };
        xhr.onerror = function () { return failureCallback('Request failed', xhr); };
        xhr.send(null);
    }
    function expandICalEvents(iCalExpander, range) {
        // expand the range. because our `range` is timeZone-agnostic UTC
        // or maybe because ical.js always produces dates in local time? i forget
        var rangeStart = common.addDays(range.start, -1);
        var rangeEnd = common.addDays(range.end, 1);
        var iCalRes = iCalExpander.between(rangeStart, rangeEnd); // end inclusive. will give extra results
        var expanded = [];
        // TODO: instead of using startDate/endDate.toString to communicate allDay,
        // we can query startDate/endDate.isDate. More efficient to avoid formatting/reparsing.
        // single events
        for (var _i = 0, _a = iCalRes.events; _i < _a.length; _i++) {
            var iCalEvent = _a[_i];
            expanded.push(__assign(__assign({}, buildNonDateProps(iCalEvent)), { start: iCalEvent.startDate.toString(), end: (specifiesEnd(iCalEvent) && iCalEvent.endDate)
                    ? iCalEvent.endDate.toString()
                    : null }));
        }
        // recurring event instances
        for (var _b = 0, _c = iCalRes.occurrences; _b < _c.length; _b++) {
            var iCalOccurence = _c[_b];
            var iCalEvent = iCalOccurence.item;
            expanded.push(__assign(__assign({}, buildNonDateProps(iCalEvent)), { start: iCalOccurence.startDate.toString(), end: (specifiesEnd(iCalEvent) && iCalOccurence.endDate)
                    ? iCalOccurence.endDate.toString()
                    : null }));
        }
        return expanded;
    }
    function buildNonDateProps(iCalEvent) {
        return {
            title: iCalEvent.summary,
            url: extractEventUrl(iCalEvent),
            extendedProps: {
                location: iCalEvent.location,
                organizer: iCalEvent.organizer,
                description: iCalEvent.description,
            },
        };
    }
    function extractEventUrl(iCalEvent) {
        var urlProp = iCalEvent.component.getFirstProperty('url');
        return urlProp ? urlProp.getFirstValue() : '';
    }
    function specifiesEnd(iCalEvent) {
        return Boolean(iCalEvent.component.getFirstProperty('dtend')) ||
            Boolean(iCalEvent.component.getFirstProperty('duration'));
    }
    var plugin = common.createPlugin({
        eventSourceDefs: [eventSourceDef],
    });

    common.globalPlugins.push(plugin);

    exports.default = plugin;

    Object.defineProperty(exports, '__esModule', { value: true });

    return exports;

}({}, FullCalendar, ICAL));
