/**
 * The Sea.js plugin for loading text resources such as template, json etc
 */

var global = window
var plugins = {}
var uriCache = {}

function register(o) {
    plugins[o.name] = o
}

// normal text
register({
    name: "text",

    ext: [".tpl", ".html"],

    exec: function(uri, content) {
        globalEval('define("' + uri + '#", [], "' + jsEscape(content) + '")')
    }
})

// json
register({
    name: "json",

    ext: [".json"],

    exec: function(uri, content) {
        globalEval('define("' + uri + '#", [], ' + content + ')')
    }
})

// for handlebars template
register({
    name: "handlebars",

    ext: [".handlebars"],

    exec: function(uri, content) {
        var code = [
            'define("' + uri + '#", ["handlebars"], function(require, exports, module) {',
            '  var source = "' + jsEscape(content) + '"',
            '  var Handlebars = require("handlebars")["default"]',
            '  module.exports = function(data, options) {',
            '    options || (options = {})',
            '    options.helpers || (options.helpers = {})',
            '    for (var key in Handlebars.helpers) {',
            '      options.helpers[key] = options.helpers[key] || Handlebars.helpers[key]',
            '    }',
            '    return Handlebars.compile(source)(data, options)',
            '  }',
            '})'
        ].join('\n')

        globalEval(code)
    }
})


seajs.on("resolve", function(data) {
    var id = data.id
    if (!id) return ""

    var pluginName
    var m

    // text!path/to/some.xx
    if ((m = id.match(/^(\w+)!(.+)$/)) && isPlugin(m[1])) {
        pluginName = m[1]
        id = m[2]
    }
    // http://path/to/a.tpl
    // http://path/to/c.json?v2
    else if ((m = id.match(/[^?]+(\.\w+)(?:\?|#|$)/))) {
        pluginName = getPluginName(m[1])
    }

    if (pluginName && id.indexOf("#") === -1) {
        id += "#"
    }

    var uri = seajs.resolve(id, data.refUri)

    if (pluginName) {
        uriCache[uri] = pluginName
    }

    data.uri = uri
})

seajs.on("request", function(data) {
    var name = uriCache[data.uri]

    if (name) {
        xhr(data.requestUri, function(content) {
            plugins[name].exec(data.uri, content)
            data.onRequest()
        })

        data.requested = true
    }
})


// Helpers

function isPlugin(name) {
    return name && plugins.hasOwnProperty(name)
}

function getPluginName(ext) {
    for (var k in plugins) {
        if (isPlugin(k)) {
            var exts = "," + plugins[k].ext.join(",") + ","
            if (exts.indexOf("," + ext + ",") > -1) {
                return k
            }
        }
    }
}

function xhr(url, callback) {
    var r = global.XMLHttpRequest ?
        new global.XMLHttpRequest() :
        new global.ActiveXObject("Microsoft.XMLHTTP")

    r.open("GET", url, true)

    r.onreadystatechange = function() {
        if (r.readyState === 4) {
            // Support local file
            if (r.status > 399 && r.status < 600) {
                throw new Error("Could not load: " + url + ", status = " + r.status)
            }
            else {
                callback(r.responseText)
            }
        }
    }

    return r.send(null)
}

function globalEval(content) {
    if (content && /\S/.test(content)) {
        (global.execScript || function(content) {
            (global.eval || eval).call(global, content)
        })(content)
    }
}

function jsEscape(content) {
    return content.replace(/(["\\])/g, "\\$1")
        .replace(/[\f]/g, "\\f")
        .replace(/[\b]/g, "\\b")
        .replace(/[\n]/g, "\\n")
        .replace(/[\t]/g, "\\t")
        .replace(/[\r]/g, "\\r")
        .replace(/[\u2028]/g, "\\u2028")
        .replace(/[\u2029]/g, "\\u2029")
}

function pure(uri) {
    // Remove timestamp etc
    return uri.replace(/\?.*$/, "")
}