var LOADING_JS_FILES = new Array();

// Can require both javascript and css files.
function require(url, onLoadCallback, isJson) {
  if (!window.includedJsUrls) {
    window.includedJsUrls = new Array();
  }
  if (includedJsUrls[url]) {
    _executeRequireCallback(onLoadCallback, url);
    return;
  }

  var newNode;
  if (url.match(/\.css$/i)) { // It's a css file
    newNode = document.createElement("link");
    newNode.setAttribute( "rel",  "stylesheet" );
    newNode.setAttribute( "type", "text/css"   );
    newNode.setAttribute( "href", url          );
    document.getElementsByTagName("head").item(0).appendChild(newNode);
  }
  else if (isJson) {
    LOADING_JS_FILES[url] = true;
    _getUrlWithAjax(url, onLoadCallback);
  }
  else { // Let's just assume it's a javascript file
    LOADING_JS_FILES[url] = true;
    var newNode = document.createElement("script");
    newNode.setAttribute( "type", "text/javascript" );
    newNode.setAttribute( "src",  url               );
    document.getElementsByTagName("head").item(0).appendChild(newNode);
    newNode.onreadystatechange = function() { // IE
      if (newNode.readyState === "complete" || newNode.readyState === "loaded") {
        delete LOADING_JS_FILES[url];
        _executeRequireCallback(onLoadCallback, url);
      }
    };
    newNode.onload = function() { // Firefox
      delete LOADING_JS_FILES[url];
      _executeRequireCallback(onLoadCallback, url);
    }
  }
  includedJsUrls[url] = true;
}

function requireJs(file, onLoadCallback) {
  _requireJsOrCss("js", file, onLoadCallback);
}

function requireJson(file, onLoadCallback) {
  _requireJsOrCss("json", file, onLoadCallback);
}

function requireCss(file, onLoadCallback) {
  _requireJsOrCss("css", file, onLoadCallback);
}

function _requireJsOrCss(type, file, onLoadCallback) {
  if (file.match(/^\//)) { // Starts with a slash
    return require(file, onLoadCallback);
  }

  var isJson = type === "json";
  if (isJson) {
    type = "js";
  }
  var customerUrl = "/" + type + "/" + file + "." + type;
  if (urlExists(customerUrl)) {
    return require(customerUrl, onLoadCallback, isJson);
  }
  var o2Url = "/o2www/" + type + "/" + file + "." + type;
  if (urlExists(o2Url)) {
    return require(o2Url, onLoadCallback, isJson);
  }
  if (window.console) {
    console.error("Couldn't require " + file);
  }
}

/* Inspired by: http://www.hunlock.com/blogs/Howto_Dynamically_Insert_Javascript_And_CSS */
function _getUrlWithAjax(url, callback) {
  var xmlHttp = _getXmlHttpRequest();
  if (!xmlHttp) {
    return false;
  }
  xmlHttp.onreadystatechange = function() {
    if (xmlHttp.readyState == 4) {
      if (xmlHttp.status == 200) {
        var jsCode = xmlHttp.responseText;
        eval(jsCode);
        delete LOADING_JS_FILES[url];
        _executeRequireCallback(callback, url);
      }
      delete xmlHttp;
    }
  }
  xmlHttp.open("GET", url + '?timestamp=' + (new Date()).getTime(), true);
  xmlHttp.send();
  return true;
}

function hasBeenRequired(url) {
  return includedJsUrls[url];
}

function _executeRequireCallback(onLoadCallback, url) {
  if (onLoadCallback) {
    onLoadCallback.call(this, url);
  }
}

function allRequiredJsFilesLoaded() {
  var count = 0;
  for (var key in LOADING_JS_FILES) {
    return false;
  }
  return true;
}

function urlExists(url) {
  var xmlHttp = _getXmlHttpRequest();
  if (!xmlHttp) {
    return false;
  }
  xmlHttp.open("HEAD", url, false);
  xmlHttp.send()
  return xmlHttp.status != 404;
}

function _getXmlHttpRequest() {
  var xmlHttp;
  if (window.XMLHttpRequest) {
    xmlHttp = new XMLHttpRequest();
  }
  else if (window.ActiveXObject) { // branch for IE/Windows ActiveX version
    try {
      xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
    }
    catch (e) {
      xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
  }
  return xmlHttp;
}

