var o2 = {};

var LOADING_JS_FILES = new Array();

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

  var newNode;
  if (url.match(/\.css$/i)) { // It's a css file
    if (!o2._validateBrowser(url)) {
      return;
    }
    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;
    o2._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];
        o2._executeRequireCallback(onLoadCallback, url);
      }
    };
    newNode.onload = function() { // Firefox
      delete LOADING_JS_FILES[url];
      o2._executeRequireCallback(onLoadCallback, url);
    }
  }
  includedJsUrls[url] = true;
}

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

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

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

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

  var isJson = type === "json";
  if (isJson) {
    type = "js";
  }
  var customerUrl = "/" + type + "/" + file + "." + type;
  if (o2.urlExists(customerUrl)) {
    return o2.require(customerUrl, onLoadCallback, isJson);
  }
  var o2Url = "/o2www/" + type + "/" + file + "." + type;
  if (o2.urlExists(o2Url)) {
    return o2.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 */
o2._getUrlWithAjax = function(url, callback) {
  var xmlHttp = o2._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];
        o2._executeRequireCallback(callback, url);
      }
      delete xmlHttp;
    }
  }
  xmlHttp.open("GET", url + '?timestamp=' + (new Date()).getTime(), true);
  xmlHttp.send();
  return true;
}

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

o2.hasBeenRequiredAndLoaded = function(url) {
  return o2.hasBeenRequired(url) && !LOADING_JS_FILES[url];
}

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

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

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

o2._getXmlHttpRequest = function() {
  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;
}

o2._validateBrowser = function(url) {
  if (url.match(/^[^.]+[.]css$/)) {
    return true;
  }
  var userAgent = navigator.userAgent.toLowerCase();
  var isIe      = userAgent.indexOf("msie")  !== -1  &&  userAgent.indexOf("opera") === -1  &&  userAgent.indexOf("webtv") === -1;
  if (!isIe) {
    return false;
  }
  var allowedIeVersion = url.replace(/^.*[.]ie(\d*)[.]css$/, "$1");
  if (!allowedIeVersion) {
    return true;
  }
  var ieVersion = parseFloat( userAgent.replace(/^.*msie ([\d.]+).*$/, "$1") );
  return parseFloat(allowedIeVersion) === ieVersion;
}

