!function(D,window,document) {
  "use strict";

  D.behaviors.dismissibleMessageBar = {
    attach: function (context, settings) {
      /**
       * Retrieve DMB Notification Settings.
       *
       * @return {Array}
       *   Array of defined DMB Settings.
       */
      const getNotificationSettings = function () {
        if (typeof(settings.dmbNotifications) !== 'undefined' && settings.dmbNotifications) {
          return settings.dmbNotifications;
        }
        return null;
      };

      /**
       * Retrieve DMB Notification Entity data.
       *
       * @return {Array}
       *   Array of defined DMB Entities.
       */
      const getNotificationEntities = function () {
        if (typeof(settings.dmbNotificationEntities) !== 'undefined' && settings.dmbNotificationEntities) {
          return settings.dmbNotificationEntities;
        }
        return null;
      };

      /**
       * Get a cookie.
       * @param {string} cname
       * @return {string|null}
       */
      const getCookie = function (cname) {
        return document.cookie.match('(^|;)\\s*' + cname + '\\s*=\\s*([^;]+)')?.pop() || null;
      }

      /**
       * Set a cookie.
       * @param {string} cname
       * @param {string} cvalue
       * @param {number} days
       */
      const setCookie = function(cname, cvalue, days) {
        const d = new Date();
        d.setTime(d.getTime() + (days * 24 * 3600000));
        const expires = "expires="+ d.toUTCString();
        document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
      }

      /**
       * Close notification functionality
       * @param $notification
       *   Notification element to be closed.
       */
      const closeNotification = function ($notification) {
        let notificationId = $notification.getAttribute('dmb-notification-id'),
          cookieExpiration = $notification.getAttribute('dmb-cookie-expiration'),
          acceptedNotifications = getCookie('dismissible_message_bar');

        if (!acceptedNotifications) {
          acceptedNotifications = notificationId;
        } else {
          acceptedNotifications = acceptedNotifications.split('.');
          if (!acceptedNotifications.includes(notificationId)) {
            acceptedNotifications.push(notificationId);
          }
          acceptedNotifications = acceptedNotifications.join('.');
        }
        // Only set cookie if cookie-off class doesn't exist.
        if(!$notification.classList.contains('cookie-off')) {
          // Set accepted cookie with updated values.
          setCookie('dismissible_message_bar', acceptedNotifications, Number(cookieExpiration));
        }

        $notification.classList.add('dismissed');
        return false;
      };

      /**
       * Inject Notifications into their respective wrappers.
       * @param {object} notificationSettings
       * @param {HTMLDivElement} $notificationWrapper
       * @param {object} requestData
       *
       */
      const injectNotifications = function (notificationSettings, $notificationWrapper, requestData) {
        // Inject notifications.
        if (notificationSettings !== null && $notificationWrapper !== null) {
          let data = getNotificationEntities();
          let dismissedNotifications = getCookie('dismissible_message_bar') ? getCookie('dismissible_message_bar').split('.') : [];
          let content = '';
          for (let key in data) {
            // Skip loop if the property is from prototype.
            if (!data.hasOwnProperty(key) || data[key].added === true) {
              continue;
            }
            if ($notificationWrapper) {
              if (data[key].content !== null) {
                let showNotification = (data[key].sitewide === 1 || data[key].sitewide === "1");

                // Check content types.
                if (data[key].contentTypes !== null && data[key].contentTypes.length !== 0 && requestData.contentType !== '') {
                  if (data[key].contentTypes.includes(requestData.contentType)) {
                    showNotification = true;
                  }
                }

                // Check path limitations.
                if (data[key].sitewide !== null && (data[key].sitewide === 0 || data[key].sitewide === "0")) {
                  if (data[key].pathLimit !== null && window.location.pathname !== '') {
                    for (let paths in data[key].pathLimit) {
                      if (!data[key].pathLimit.hasOwnProperty(paths)) {
                        continue;
                      }

                      let searchPath = data[key].pathLimit[paths];
                      let isNot = false;
                      if (searchPath.indexOf("!") === 0) {
                        // This is a NOT path.
                        isNot = true;
                        searchPath = searchPath.slice(1);
                      }

                      if (searchPath === window.location.pathname || searchPath === window.location.pathname + window.location.search) {
                        showNotification = !isNot;
                        break;
                      }
                      else {
                        if (searchPath.indexOf("*") !== -1) {
                          // This is a wildcard search. Replace the * with a .*
                          searchPath.replaceAll(/\*/g, ".*");
                          let fullPath = window.location.pathname + window.location.search;
                          if (window.location.pathname.search(searchPath) !== -1 || fullPath.search(searchPath) !== -1) {
                            showNotification = true;
                            break;
                          }
                        }
                      }
                    }
                  }
                }

                // Check for excluded paths.
                if (data[key].excluded !== null && window.location.pathname !== '') {
                  for (let paths in data[key].excluded) {
                    if (!data[key].excluded.hasOwnProperty(paths)) {
                      continue;
                    }

                    let searchPath = data[key].excluded[paths];

                    if (searchPath === window.location.pathname || searchPath === window.location.pathname + window.location.search) {
                      showNotification = false;
                      break;
                    }
                    else {
                      if (searchPath.indexOf("*") !== -1) {
                        // This is a wildcard search. Replace the * with a .*
                        searchPath.replace(/\*/g, ".*");
                        if (window.location.pathname.search(searchPath) !== -1) {
                          showNotification = false;
                          break;
                        }
                      }
                    }
                  }
                }


                // Check if this notification has been dismissed
                if (dismissedNotifications.includes(data[key].id)) {
                  showNotification = false;
                }

                // Check date limitations
                if (showNotification) {
                  let nowDate = new Date();
                  if (data[key].startTime !== null && data[key].startTime !== "") {
                    let startDate = new Date(data[key].startTime);
                    if (startDate instanceof Date && !isNaN(startDate)) {
                      if (startDate.valueOf() > nowDate.valueOf()) {
                        // This notification should not appear yet.
                        showNotification = false;
                      }
                    }
                  }
                  if (showNotification && data[key].endTime !== null && data[key].endTime !== "") {
                    let endDate = new Date(data[key].endTime);
                    if (endDate instanceof Date && !isNaN(endDate)) {
                      if (nowDate.valueOf() > endDate.valueOf()) {
                        // This notification has passed.
                        showNotification = false;
                      }
                    }
                  }
                }

                if (showNotification) {
                  content += data[key].content;
                  data[key].added = true;
                }
              }
            }
          }
          if (content !== '') {
            $notificationWrapper.innerHTML = content;
            // Dispatch custom event.
            $notificationWrapper.dispatchEvent(new Event('injectDMBNotifications'));
          }

        }

      };

      /**
       * Event handler to close notification. Only runs once.
       *
       * @param {Event} e
       */
      function handleCloseNotification (e) {
        e.preventDefault();
        closeNotification(this.parentElement);
        this.removeEventListener(e.type, handleCloseNotification);
      }

      // Initialize notifications.
      let settingsObject = getNotificationSettings();
      let notificationSettingsArray = Object.values(settingsObject);
      for (let i in notificationSettingsArray) {
        let notificationSettings = notificationSettingsArray[i];
        let $notificationWrapper = null,
          $overlayWrapper = null,
          requestData = {
            contentType: '',
            contentPath: '',
            notificationType: '',
          };

        if (typeof(notificationSettings.notificationWrapper) !== 'undefined' && notificationSettings.notificationWrapper) {
          $notificationWrapper = document.querySelector(`${notificationSettings.notificationWrapper}`);
        }

        if (typeof(notificationSettings.overlayWrapper) !== 'undefined' && notificationSettings.overlayWrapper) {
          $overlayWrapper = document.querySelector(`${notificationSettings.overlayWrapper}`);
        }

        // These parameters have to be saved and passed into the handler.
        if (typeof(notificationSettings.contentType) !== 'undefined' && notificationSettings.contentType) {
          requestData.contentType = notificationSettings.contentType;
        }

        if (typeof(notificationSettings.contentPath) !== 'undefined' && notificationSettings.contentPath) {
          requestData.contentPath = notificationSettings.contentPath;
        }

        if (typeof(notificationSettings.notificationType) !== 'undefined' && notificationSettings.notificationType) {
          requestData.notificationType = notificationSettings.notificationType;
        }

        if ($notificationWrapper !== null && !$notificationWrapper.hasAttribute('injected-dmb-notification')) {
          // Set this attribute to ensure the event listeners get attached once.
          $notificationWrapper.setAttribute('injected-dmb-notification', 'true');
          $notificationWrapper.addEventListener('injectDMBNotifications', function () {
            // Set timer on auto dismiss.
            const $autoDismiss = this.querySelectorAll('[dmb-auto-dismiss="1"]');
            $autoDismiss.forEach(function (el) {
              const time = +el.getAttribute('dmb-dismiss-time') * 1000;
              setTimeout(() => {
                closeNotification(el);
              }, time);
            });
            // Add events to close.
            const $closeNotificationTriggers = this.querySelectorAll('.dmb-notification .close-dmb-notification');
            $closeNotificationTriggers.forEach((anchor) => {
              // These will run once.
              anchor.addEventListener('click', handleCloseNotification);
              anchor.addEventListener('touchstart', handleCloseNotification);
            });
          });
        }

        injectNotifications(notificationSettings, $notificationWrapper, requestData);

      }

    }
  };

}(Drupal,window,document);