//>>excludeStart('excludeAfterBuild', pragmas.excludeAfterBuild)
define(['handlebars', "underscore"], function(Handlebars, _) {

    function replaceLocaleStrings(ast, mapping, options) {
        options = options || {};
        mapping = mapping || {};
        // Base set of things
        if (ast && ast.type === "program" && ast.statements) {
            _(ast.statements).forEach(function(statement, i) {
                var newString = "<!-- i18n error -->";
                // If it's a translation node
                if (statement.type === "mustache" && statement.id && statement.id.original === "$") {

                    if (statement.params.length && statement.params[0].string) {
                        var key = statement.params[0].string;
                        newString = mapping[key] || (options.originalKeyFallback ? key : newString);
                    }
                    ast.statements[i] = new Handlebars.AST.ContentNode(newString);
                }
                // If we need to recurse
                else if (statement.program) {
                    statement.program = replaceLocaleStrings(statement.program, mapping, options);
                }
            });
            // Also cover the else blocks
            if (ast.inverse) {
                replaceLocaleStrings(ast.inverse, mapping, options);
            }
        }
        return ast;
    }

    return function precompile(string, mapping, options) {
        var ast, environment;

        options = options || {};

        if (!('data' in options)) {
            options.data = true;
        }

        if (options.compat) {
            options.useDepths = true;
        }

        ast = Handlebars.parse(string);

        // avoid replacing locale if mapping is `false`
        if (mapping !== false) {
            ast = replaceLocaleStrings(ast, mapping, options);
        }

        environment = new Handlebars.Compiler().compile(ast, options);
        return new Handlebars.JavaScriptCompiler().compile(environment, options);
    };
});
//>>excludeEnd('excludeAfterBuild')
