var entityMap = require(“../maps/entities.json”),

legacyMap = require("../maps/legacy.json"),
xmlMap    = require("../maps/xml.json"),
decodeCodePoint = require("./decode_codepoint.js");

var decodeXMLStrict = getStrictDecoder(xmlMap),

decodeHTMLStrict = getStrictDecoder(entityMap);

function getStrictDecoder(map){

var keys = Object.keys(map).join("|"),
    replace = getReplacer(map);

keys += "|#[xX][\\da-fA-F]+|#\\d+";

var re = new RegExp("&(?:" + keys + ");", "g");

return function(str){
        return String(str).replace(re, replace);
};

}

var decodeHTML = (function(){

var legacy = Object.keys(legacyMap)
        .sort(sorter);

var keys = Object.keys(entityMap)
        .sort(sorter);

for(var i = 0, j = 0; i < keys.length; i++){
        if(legacy[j] === keys[i]){
                keys[i] += ";?";
                j++;
        } else {
                keys[i] += ";";
        }
}

var re = new RegExp("&(?:" + keys.join("|") + "|#[xX][\\da-fA-F]+;?|#\\d+;?)", "g"),
    replace = getReplacer(entityMap);

function replacer(str){
        if(str.substr(-1) !== ";") str += ";";
        return replace(str);
}

//TODO consider creating a merged map
return function(str){
        return String(str).replace(re, replacer);
};

}());

function sorter(a, b){

return a < b ? 1 : -1;

}

function getReplacer(map){

return function replace(str){
        if(str.charAt(1) === "#"){
                if(str.charAt(2) === "X" || str.charAt(2) === "x"){
                        return decodeCodePoint(parseInt(str.substr(3), 16));
                }
                return decodeCodePoint(parseInt(str.substr(2), 10));
        }
        return map[str.slice(1, -1)];
};

}

module.exports = {

XML: decodeXMLStrict,
HTML: decodeHTML,
HTMLStrict: decodeHTMLStrict

};