(function () {
    var C = typeof window === 'undefined' ? require('./Crypto').Crypto : window.Crypto;

    // Shortcuts
    var util = C.util;
    var charenc = C.charenc;
    var UTF8 = charenc.UTF8;
    var Binary = charenc.Binary; // Public API
    var SHA1 = (C.SHA1 = function (message, options) {
        var digestbytes = util.wordsToBytes(SHA1._sha1(message));
        return options && options.asBytes ? digestbytes : options && options.asString ? Binary.bytesToString(digestbytes) : util.bytesToHex(digestbytes);
    });

    // The core
    SHA1._sha1 = function (message) {
        // Convert to byte array
        if (message.constructor == String) {
            message = UTF8.stringToBytes(message);
        }
        /* else, assume byte array already */
        var m = util.bytesToWords(message);
        var l = message.length * 8;
        var w = [];
        var H0 = 1732584193;
        var H1 = -271733879;
        var H2 = -1732584194;
        var H3 = 271733878;
        var H4 = -1009589776; // Padding
        m[l >> 5] |= 128 << (24 - (l % 32));
        m[(((l + 64) >>> 9) << 4) + 15] = l;
        for (var i = 0; i < m.length; i += 16) {
            var a = H0;
            var b = H1;
            var c = H2;
            var d = H3;
            var e = H4;
            for (var j = 0; j < 80; j++) {
                if (j < 16) {
                    w[j] = m[i + j];
                } else {
                    var n = w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16];
                    w[j] = (n << 1) | (n >>> 31);
                }
                var t =
                    ((H0 << 5) | (H0 >>> 27)) +
                    H4 +
                    (w[j] >>> 0) +
                    (j < 20
                        ? ((H1 & H2) | (~H1 & H3)) + 1518500249
                        : j < 40
                        ? (H1 ^ H2 ^ H3) + 1859775393
                        : j < 60
                        ? ((H1 & H2) | (H1 & H3) | (H2 & H3)) - 1894007588
                        : (H1 ^ H2 ^ H3) - 899497514);
                H4 = H3;
                H3 = H2;
                H2 = (H1 << 30) | (H1 >>> 2);
                H1 = H0;
                H0 = t;
            }
            H0 += a;
            H1 += b;
            H2 += c;
            H3 += d;
            H4 += e;
        }
        return [H0, H1, H2, H3, H4];
    };

    // Package private blocksize
    SHA1._blocksize = 16;
    SHA1._digestsize = 20;
})();
