// IE compatibility
if (window.navigator.userAgent.indexOf("MSIE ") > -1 || window.navigator.userAgent.indexOf("Trident") > -1) {
  // forEach polyfill
  if (!Array.prototype.forEach) {
    Array.prototype.forEach = function(fn, scope) {
      for(var i = 0, len = this.length; i < len; ++i) {
        fn.call(scope, this[i], i, this);
      }
    }
  }
  if (window.NodeList && !NodeList.prototype.forEach) {
    NodeList.prototype.forEach = function (callback, thisArg) {
      thisArg = thisArg || window;
      for (var i = 0; i < this.length; i++) {
        callback.call(thisArg, this[i], i, this);
      }
    };
  }

  // ChildNode.after() polyfill
  (function(x){
   var o=x.prototype;
   o.after||(o.after=function(){var e,m=arguments,l=m.length,i=0,t=this,p=t.parentNode,n=Node,s=String,d=document;if(p!==null){while(i<l){((e=m[i]) instanceof n)?(((t=t.nextSibling )!==null)?p.insertBefore(e,t):p.appendChild(e)):p.appendChild(d.createTextNode(s(e)));++i;}}});
  }(Element));
}
// End IE compatibility

(function(){
  var nitroLoaded = false;
  var documentReady = [];// array of tuples in the form [handler, isJquery]. If isJquery is true then we will use $() for firing the handler
  var readyEvent = null;

  if ("addEventListener" in window) {
    document.addEventListener("DOMContentLoaded", function (e) {
      readyEvent = e;
    });

    document.defaultAddEventListener = document.addEventListener;
    document.triggerNitroLoad = function () {
      nitroLoaded = true;
      documentReady.forEach(function(handlerTuple){
        try {
          if (handlerTuple[1] && typeof jQuery != 'undefined') {//fire jQuery's ready method
            jQuery(handlerTuple[0]);
          } else {
            handlerTuple[0](readyEvent);
          }
        } catch (e) {
          console.log("Document ready handler error: " + e.message);
        }
      });
    }

    document.jQueryReady = function (handler) {
        documentReady.push([handler, true]);
    }

    document.addEventListener = function (type, handler) {
      if (type == 'DOMContentLoaded' && !nitroLoaded) {
        documentReady.push([handler, false]);
      } else {
        document.defaultAddEventListener(type, handler);
      }
    }
  }
})();

(function(){
  var nitroLoaded = false;
  var windowLoad = [];
  var onloadEvent = null;

  function fireOnLoad() {
    windowLoad.forEach(function(handler){
      try {
        handler(onloadEvent);
      } catch (e) {
        console.log("Window load handler error: " + e.message);
      }
    });
  }

  if ("addEventListener" in window) {
    window.addEventListener("load", function (e) {
      onloadEvent = e;
      if (nitroLoaded) {
        fireOnLoad();
      }
    });

    window.defaultAddEventListener = window.addEventListener;
    window.triggerNitroLoad = function () {
      nitroLoaded = true;
      if (onloadEvent) {
        fireOnLoad();
      }
    }

    window.addEventListener = function () {
      if (arguments.length < 2) {
        window.defaultAddEventListener.apply(null, arguments);
      }

      var type = arguments[0];
      var handler = arguments[1];

      if (type == 'load' && !nitroLoaded) {
        windowLoad.push(handler);
      } else {
        window.defaultAddEventListener.apply(null, arguments);
      }
    }
  }
})();

NitroWindowOnLoad = (function() {
  var fired = false;
  var handlersQueue = [];

  return {
    fire: function() {
      if (!fired) {
        fired = true;

        if (this.callback) {
          this.callback();
        }

        if (handlersQueue.length > 0) {
          do {
            try {
              (handlersQueue.shift())();
            } catch (e) {
              console.log("Window load handler error: " + e.message);
            }
          } while(handlersQueue.length > 0);
        }
      }
    },
    add: function(callback) {
      if (fired) {
        callback();
      } else {
        handlersQueue.push(callback);
      }
    },
    callback: null
  }
})();

var NitroResourceLoader = (function() {
  var autoRemoveCriticalCss = {BASE_CSS_AUTO_REMOVE};

  var stylesQueue = [];
  var styleQueueSize = 0;

  var scriptsQueue = [];
  var remoteScriptQueueSize = 0;

  var holdingJquery = false;

  var onloadScript = function(e) {
    if (!holdingJquery && typeof jQuery != 'undefined' && jQuery.holdReady) {
      jQuery.holdReady(true);
      holdingJquery = true;
      console.log("Holding jQuery");
    }

    if (--remoteScriptQueueSize == 0 && scriptsQueue.length == 0) {
      triggerPageLoad();
    }
  }

  var injectInlineScript = function(id) {
    var inlineScript = document.getElementById(id);
    var script = document.createElement('script');
    var src = inlineScript.innerHTML.replace('window.onload', 'NitroWindowOnLoad.callback');
    src = src.replace('$(window).load', 'NitroWindowOnLoad.add');
    //src = src.replace(/[\w$_]+\(document\)\.ready\(/, 'document.jQueryReady(');
    script.innerHTML = src.replace(/^(?:<!--)?(.*?)(?:-->)?$/gm, '$1');
    try {
      document.head.appendChild(script);
    } catch (e) {
      console.log("Inline script error: " + e.message);
    }

    if (remoteScriptQueueSize == 0 && scriptsQueue.length == 0) {
      triggerPageLoad();
    }
  }

  var triggerPageLoad = function() {
      if (holdingJquery) {
        console.log("Releasing jQuery");
        jQuery.holdReady(false);
      }
      document.triggerNitroLoad();
      window.triggerNitroLoad();
      NitroWindowOnLoad.fire();
  }

  var loadQueuedScripts = function() {
    var scriptInfo = scriptsQueue.shift();

    while (scriptInfo) {
      switch (scriptInfo.type) {
        case "remote":
          var script = document.createElement('script');
          script.src = scriptInfo.src;
          script.async = false;
          script.addEventListener("load", onloadScript);
          script.addEventListener("load", loadQueuedScripts);
          script.addEventListener("error", onloadScript);
          script.addEventListener("error", loadQueuedScripts);
          document.head.appendChild(script);
          return;
        case "inline":
          injectInlineScript(scriptInfo.id);
          break;
      }

      scriptInfo = scriptsQueue.shift();
    }
  }

  var loadQueuedStyles = function() {
    var stylesParent = document.getElementById('nitro-deferred-styles');
    var div = document.createElement('div');
    div.innerHTML = stylesParent.textContent;
    styleQueueSize = div.querySelectorAll('[nitro-rel="stylesheet"]').length;
    var baseCss = document.getElementById('nitro-base-css');
    if (baseCss) {
      baseCss.after(div);
    } else {
      document.body.appendChild(div);
    }

    var script = document.createElement('script');
    script.innerHTML = document.getElementById('nitropack-cssrelpreload').innerHTML;
    document.head.appendChild(script);
  }

  return {
    setAutoRemoveCriticalCss: function (flag) {
      autoRemoveCriticalCss = flag;
    },
    registerScript: function(src) {
      scriptsQueue.push({
        type: "remote",
        src: src
      });
      remoteScriptQueueSize++;
    },
    registerInlineScript: function(id) {
      scriptsQueue.push({
        type: "inline",
        id: id
      });
    },
    registerStyle: function(href, rel, media) {
      stylesQueue.push({
        href: href,
        rel: rel,
        media: media
      });
    },
    onLoadStyle: function(style) {
      if (--styleQueueSize == 0) {
        document.querySelectorAll("link[rel='preload'][nitro-rel]").forEach(function(style) {
          style.rel = style.getAttribute('nitro-rel');
        });

        if (autoRemoveCriticalCss) {
          var baseCssElement = document.getElementById('nitro-base-css');
          if (baseCssElement) {
            baseCssElement.remove();
          }
        }
        
        loadQueuedScripts();
      }
    },
    onErrorStyle: function(style) {
      if (--styleQueueSize == 0) {
        loadQueuedScripts();
      }
    },
    loadQueuedResources: function() {
      var raf = requestAnimationFrame || mozRequestAnimationFrame ||
          webkitRequestAnimationFrame || msRequestAnimationFrame;

      if (raf) raf(function() { window.setTimeout(loadQueuedStyles, 0); });
      else window.defaultAddEventListener('load', loadQueuedStyles);
    }
  }
})();
