var punycode = require('punycode');
var entities = require('./entities.json');

module.exports = decode;

function decode (str) {
    if (typeof str !== 'string') {
        throw new TypeError('Expected a String');
    }

    return str.replace(/&(#?[^;\W]+;?)/g, function (_, match) {
        var m;
        if (m = /^#(\d+);?$/.exec(match)) {
            return punycode.ucs2.encode([ parseInt(m[1], 10) ]);
        } else if (m = /^#[Xx]([A-Fa-f0-9]+);?/.exec(match)) {
            return punycode.ucs2.encode([ parseInt(m[1], 16) ]);
        } else {
            // named entity
            var hasSemi = /;$/.test(match);
            var withoutSemi = hasSemi ? match.replace(/;$/, '') : match;
            var target = entities[withoutSemi] || (hasSemi && entities[match]);

            if (typeof target === 'number') {
                return punycode.ucs2.encode([ target ]);
            } else if (typeof target === 'string') {
                return target;
            } else {
                return '&' + match;
            }
        }
    });
}
