/**
 * @author dstott
 */

if (typeof CORDA == "undefined")
{
    var CORDA = {};
}

CORDA.userAgent = navigator.userAgent;
CORDA.globalScope = window;
if (typeof CORDA.loaded == "undefined")
{
    CORDA.loaded = {};
}

if (typeof CORDA.ensured == "undefined")
{
    CORDA.ensured = {};
}
CORDA.ensuredLoadedTries = 0;

CORDA.include = function(url)
{
    if (!CORDA.loaded[url])
    {
        if (CORDA.isFirefox()) // firefox 1.5+ only
        {
            var newScript = document.createElement("script");
            newScript.src = url;
            CORDA.appendScript(newScript);
            CORDA.loaded[url] = true;
        }
        else
        {
            var contents = CORDA.loadFromUrl(url);
            if (contents)
            {
                try
                {
                    CORDA.evaluate(contents);
                    CORDA.loaded[url] = true;
                }
                catch (e)
                {
                    if (e == "evaluate")
                    {
                        CORDA.handleError("Unable to evaluate the contents of: " + url);
                    }
                    else
                    {
                        CORDA.handleError("Error: " + e);
                    }
                }
            }
        }
    }
    return CORDA.loaded[url];
}

CORDA.require = function(pkg, url)
{
    if (!CORDA.loaded[url])
    {
        if (CORDA.isFirefox3OrOlder()) // firefox only
        {
            var newScript = document.createElement("script");
            newScript.src = url;
            CORDA.appendScript(newScript);
            CORDA.loaded[url] = true;
        }
        else
        {
            var contents = CORDA.loadFromUrl(url);
            if (contents)
            {
                try
                {
                    var classdef = CORDA.evaluate(contents, pkg);
                    if (typeof classdef != 'undefined')
                    {
                        CORDA.loaded[url] = true;
                    }
                }
                catch (e)
                {
                    if (e == "evaluate")
                    {
                        CORDA.handleError("Unable to evaluate the contents of: " + url);
                    }
                    else
                    {
                        CORDA.handleError("Package not found: " + pkg + ", " + e);
                    }
                }
            }
        }
    }
    return CORDA.loaded[url];
}

CORDA.ensure = function(testObject, url, tries)
{
    if (!tries || tries == undefined)
    {
        tries = 0;
    }
    if (tries < 100)
    {
        if (!CORDA.loaded[url])
        {
            CORDA.require('CORDA', url);
        }
        if (!CORDA.ensured[testObject])
        {
            var defined = false;
            try {if (window.eval(testObject) !== undefined ) defined = true;}
            catch (e) {}
            if (!defined)
            {
                CORDA.ensured[testObject] = false;
                setTimeout("CORDA.ensure('" + testObject + "','" + url + "'," + ++tries + ")", 10);
                return;
            }
        }
    }
    CORDA.ensured[testObject] = true;
}

CORDA.ensuredLoaded = function()
{
    CORDA.ensuredLoadedTries++;
    if (CORDA.ensuredLoadedTries > 200) return true;
    if (CORDA.ensured.length == 0) return false;
    for (var v in CORDA.ensured)
    {
        if (!CORDA.ensured[v])
        {
            return false;
        }
    }
    CORDA.ensuredLoadedTries = 0;
    return true;
}

CORDA.includeCss = function (url) {

    // We are preventing loading a file already loaded
    if (CORDA.loaded[url]) return;

    var links = document.getElementsByTagName("link");
    for (var i = 0; i < links.length ; i++)
    {
        if (links[i].getAttribute('href').indexOf(url) >=0)
        {
            CORDA.loaded[url] = true;
            return;
        }
    }

    var cssEl = document.createElement("link");
    cssEl.setAttribute("rel", "stylesheet");
    cssEl.setAttribute("type", "text/css");
    cssEl.setAttribute("href", url);

    var head = document.getElementsByTagName("head")[0];
    head.appendChild(cssEl);
    if (url.indexOf("%%corda-inactive%%") < 0) CORDA.loaded[url] = true;
}

CORDA.evaluate = function(contents, pkg)
{
    var success;
    try
    {
        success = this.globalEval(contents);
    }
    catch (e)
    {
        if (e)
        {
            throw "evaluate";
        }
    }
    if (success && pkg)
    {
        return window.eval(pkg);
    }
}

CORDA.globalEval = function(js)
{
    var success = true;
    if (typeof js != "string")
    {
        return false;
    }

    // Check whether window.eval executes code in the global scope.
    window.eval("var CORDA_INCLUDE_TEST_1 = true;");
    if (typeof window.CORDA_INCLUDE_TEST_1 != "undefined")
    {
        delete window.CORDA_INCLUDE_TEST_1;
        window.eval(js);
    }
    else if (typeof window.execScript != "undefined")	// IE only
    {
        window.execScript(js);
    }
    else
    {
        // Test effectiveness of creating a new SCRIPT element and adding it to the document.
        this.insertScriptTag = function (jsCode)
        {
            var script = document.createElement("script");
            script.type = "text/javascript";
            script.defer = false;
            script.text = jsCode;
            var headNodeSet = document.getElementsByTagName("head");
            if (headNodeSet.length)
            {
                script = headNodeSet.item(0).appendChild(script);
            }
            else
            {
                var head = document.createElement("head");
                head = document.documentElement.appendChild(head);
                script = head.appendChild(script);
            }
            return script;
        }
        var testScript = this.insertScriptTag("var CORDA_INCLUDE_TEST_2 = true;");
        if (typeof window.CORDA_INCLUDE_TEST_2 == "boolean")
        {
            testScript.parentNode.removeChild(testScript);
            this.insertScriptTag(js);
        }
        else
        {
            // Check whether window.setTimeout works in real time.
            window.setTimeout("var CORDA_INCLUDE_TEST_3 = true;", 0);
            if (typeof window.CORDA_INCLUDE_TEST_3 != "undefined")
            {
                delete window.CORDA_INCLUDE_TEST_3;
                window.setTimeout(js, 0);
            }
            else
            {
                js.replace(/\\/g,'\\\\').replace(/"/g,'\\"').replace(/\n/g,"\\n");
		        window.setTimeout(js, 0);
                this.sleep(100); // wait for js to get into global space
                if (typeof window.CORDA_INCLUDE_TEST_3 != "undefined")
                {
                    delete window.CORDA_INCLUDE_TEST_3;
                }
                if (this.isSafari())
                {
                    success = false;
                }
            }
        }
    }

    return success;
}

CORDA.loadFromUrl = function (url)
{
    return new CORDA.Request().getText(url);
}

// Low-Level HTTP Request
CORDA.Request = function()
{
    if (CORDA.globalScope.XMLHttpRequest)
    {
        this.req = new XMLHttpRequest();
    }
    else
    {
        this.req = new ActiveXObject("Microsoft.XMLHTTP");
    }
}

CORDA.handleError = function (msg, level)
{
    if (!level)
    {
        level = CORDA.errorLevel;
    }
    CORDA.errorMessage = msg;

    switch (level)
    {
        case "none":
            break;
        case "warn":
            alert(msg);
            break;
        case "die":
        default:
            throw new Error(msg);
            break;
    }
}

CORDA.sleep = function (numberMillis)
{
    var now = new Date();
    var exitTime = now.getTime() + numberMillis;
    while (true)
    {
        now = new Date();
        if (now.getTime() > exitTime)
        {
            return;
        }
    }
}

CORDA.appendScript = function(newScript)
{
    if (document.getElementsByTagName("body") && document.getElementsByTagName("body")[0])
    {
        document.getElementsByTagName("body")[0].appendChild(newScript);
    }
    else
    {
        var scripts = document.getElementsByTagName("script");
        var target = scripts[scripts.length - 1];
        target.parentNode.insertBefore(newScript, target.nextSibling);
    }
}

CORDA.isOpera = function()
{
  return /Opera/.test(CORDA.userAgent);
}

CORDA.isSafari = function()
{
  return /Safari/.test(CORDA.userAgent);
}

CORDA.isGecko = function()
{
  return navigator.product == "Gecko" && !( this.isOpera() || this.isSafari() );
}

CORDA.isIEWin = function()
{
  return window.external && /Win/.test(CORDA.userAgent);
}

CORDA.isIEMac = function()
{
  return window.external && /Mac/.test(CORDA.userAgent);
}

CORDA.isFirefox3OrOlder = function()
{
  if (CORDA.isFirefox())
  {
    var ffVersion = CORDA.userAgent.substr(CORDA.userAgent.indexOf('Firefox/')+8).split('\.')[0];
    //console.log('Firefox version detected: ' + ffVersion);
    return ffVersion < 4;
  }
  return false;
}

CORDA.isFirefox = function()
{
   return Array.every;
}

CORDA.Request.prototype =
{
    req:  null,

    getText: function (url)
    {
        this.req.open("GET", url, false);
        try
        {
            this.req.send(null);
            var stat = this.req.status;
            //           OK   Not Modified    IE Cached   Safari cached
            if (stat == 200 || stat == 304 || stat == 0 || stat == null)
            {
                var r = this.req.responseText;
                this.req = null;
                return r;
            }

        }
        catch (e)
        {
            CORDA.handleError("File not found: " + url + ", " + e);
            return null;
        };

        CORDA.handleError("File not found: " + url);
        return null;
    }
};
