'use strict';

/*@
Ox.get <f> Get a remote file
    # fixme: remote? same-origin-policy? jsonp?
    (url, callback) -> <u> undefined
    url <s> Remote URL
    callback <f> Callback function
        data <s> The contents of the remote resource
@*/
Ox.get = function(url, callback) {
    var req = new XMLHttpRequest();
    req.open('GET', url, true);
    req.onreadystatechange = function() {
        if (req.readyState == 4) {
            if (req.status == 200) {
                callback(req.responseText);
            } else {
                throw new Error(
                    'Cannot get URL "' + url + '" (Status: ' + req.status + ')'
                );
            }
        }
    };
    req.send();                
};

/*@
Ox.getJSON <f> Get and parse a remote JSON file
    # fixme: remote? same-origin-policy? jsonp?
    (url, callback) -> <u> undefined
    url <s> Remote URL
    callback <f> Callback function
        data <s> The parsed contents of the remote resource
@*/
Ox.getJSON = function(url, callback) {
    Ox.get(url, function(data) {
        callback(JSON.parse(data));
    });
};

/*@
Ox.getJSONC <f> Get and parse a remote JSONC file
    JSONC is JSON with JavaScript line or block comments
    (url, callback) -> <u> undefined
    url <s> Remote URL
    callback <f> Callback function
        data <s> The parsed contents of the remote resource
@*/
Ox.getJSONC = function(url, callback) {
    Ox.get(url, function(data) {
        callback(JSON.parse(Ox.minify(data)));
    });
};

/*@
Ox.loadFile <f> Loads a file (image, script or stylesheet)
    (file="script.js", callback)      -> <u> undefined
    (file="stylesheet.css", callback) -> <u> undefined
    (file="image.png", callback)      -> <e> DOM element
    file     <s> Local path or remote URL
    callback <f> Callback function
@*/
Ox.loadFile = (function() {
    // fixme: this doesn't handle errors yet
    // fixme: rename to getFile?
    // fixme: what about array of files?
    var cache = {};
    return function (file, callback) {
        var element,
            request,
            type = file.split('.').pop(),
            isImage = type != 'css' && type != 'js';
        if (!cache[file]) {
            if (isImage) {
                element = new Image();
                element.onload = addFileToCache;
                element.src = file;
            } else {
                if (!findFileInHead()) {
                    element = document.createElement(
                        type == 'css' ? 'link' : 'script'
                    );
                    element[type == 'css' ? 'href' : 'src'] = file + '?' + Ox.random(1000000);
                    element.type = type == 'css' ? 'text/css' : 'text/javascript';
                    if (/MSIE/.test(navigator.userAgent)) {
                        // fixme: find a way to check if css/js have loaded in msie
                        setTimeout(addFileToCache, 2500);
                    } else {
                        if (type == 'css') {
                            element.rel = 'stylesheet';
                            waitForCSS();
                        } else {
                            element.onload = addFileToCache;
                        }                        
                    }
                    document.head.appendChild(element);
                } else {
                    addFileToCache();
                }
            }
        } else {
            callback();
        }
        function addFileToCache() {
            if (isImage) {
                // for an image, save the element itself,
                // so that it remains in the browser cache
                cache[file] = element;
                callback(element);
            } else {
                cache[file] = true;
                callback();
            }
        }
        function findFileInHead() {
            return Ox.makeArray(
                document.getElementsByTagName(type == 'css' ? 'link' : 'script')
            ).map(function(element) {
                return element[type == 'css' ? 'href' : 'src'] == file;
            }).reduce(function(prev, curr) {
                return prev || curr; 
            }, false);
        }
        function waitForCSS() {
            var error = false;
            try {
                element.sheet.cssRule;
            } catch(e) {
                error = true;
                setTimeout(function() {
                    waitForCSS();
                }, 25);
            }
            !error && addFileToCache();
        }
    };
}());